1use std::collections::HashMap;
2use std::sync::{Arc, Weak};
34use atomic_refcell::AtomicRefCell;
5use rand::seq::IndexedRandom;
67use crate::host::descriptor::listener::{StateEventSource, StateListenHandle, StateListenerFilter};
8use crate::host::descriptor::socket::unix::{UnixSocket, UnixSocketType};
9use crate::host::descriptor::{FileSignals, FileState};
1011struct NamespaceEntry {
12/// The bound socket.
13socket: Weak<AtomicRefCell<UnixSocket>>,
14/// The event listener handle, which removes the listener when dropped.
15_handle: StateListenHandle,
16}
1718impl NamespaceEntry {
19pub fn new(socket: Weak<AtomicRefCell<UnixSocket>>, handle: StateListenHandle) -> Self {
20Self {
21 socket,
22 _handle: handle,
23 }
24 }
25}
2627pub struct AbstractUnixNamespace {
28 address_map: HashMap<UnixSocketType, HashMap<Vec<u8>, NamespaceEntry>>,
29}
3031impl AbstractUnixNamespace {
32pub fn new() -> Self {
33let mut rv = Self {
34// initializes an empty hash map for each unix socket type
35address_map: HashMap::new(),
36 };
3738// the namespace code will assume that there is an entry for each socket type
39rv.address_map
40 .insert(UnixSocketType::Stream, HashMap::new());
41 rv.address_map.insert(UnixSocketType::Dgram, HashMap::new());
42 rv.address_map
43 .insert(UnixSocketType::SeqPacket, HashMap::new());
4445 rv
46 }
4748pub fn lookup(
49&self,
50 sock_type: UnixSocketType,
51 name: &[u8],
52 ) -> Option<Arc<AtomicRefCell<UnixSocket>>> {
53// the unwrap() will panic if the socket was dropped without being closed, but this should
54 // only be possible at the end of the simulation and there wouldn't be any reason to call
55 // lookup() at that time, so a panic here would most likely indicate an issue somewhere else
56 // in shadow
57self.address_map
58 .get(&sock_type)
59 .unwrap()
60 .get(name)
61 .map(|x| x.socket.upgrade().unwrap())
62 }
6364pub fn bind(
65 ns_arc: &Arc<AtomicRefCell<Self>>,
66 sock_type: UnixSocketType,
67mut name: Vec<u8>,
68 socket: &Arc<AtomicRefCell<UnixSocket>>,
69 socket_event_source: &mut StateEventSource,
70 ) -> Result<(), BindError> {
71// make sure we aren't wasting memory since we don't mutate the name
72name.shrink_to_fit();
7374let mut ns = ns_arc.borrow_mut();
75let name_copy = name.clone();
7677// look up the name in the address map
78let entry = match ns.address_map.get_mut(&sock_type).unwrap().entry(name) {
79 std::collections::hash_map::Entry::Occupied(_) => return Err(BindError::NameInUse),
80 std::collections::hash_map::Entry::Vacant(x) => x,
81 };
8283// when the socket closes, remove this entry from the namespace
84let handle =
85Self::on_socket_close(Arc::downgrade(ns_arc), socket_event_source, move |ns| {
86assert!(ns.unbind(sock_type, &name_copy).is_ok());
87 });
8889 entry.insert(NamespaceEntry::new(Arc::downgrade(socket), handle));
9091Ok(())
92 }
9394pub fn autobind(
95 ns_arc: &Arc<AtomicRefCell<Self>>,
96 sock_type: UnixSocketType,
97 socket: &Arc<AtomicRefCell<UnixSocket>>,
98 socket_event_source: &mut StateEventSource,
99mut rng: impl rand::Rng,
100 ) -> Result<Vec<u8>, BindError> {
101let mut ns = ns_arc.borrow_mut();
102103// the unused name that we will bind the socket to
104let mut name = None;
105106// try 10 random names
107for _ in 0..10 {
108let random_name: [u8; NAME_LEN] = random_name(&mut rng);
109110if !ns
111 .address_map
112 .get(&sock_type)
113 .unwrap()
114 .contains_key(&random_name[..])
115 {
116 name = Some(random_name.to_vec());
117break;
118 }
119 }
120121// if unsuccessful, try a linear search through all valid names
122if name.is_none() {
123for x in 0..CHARSET.len().pow(NAME_LEN as u32) {
124let temp_name: [u8; NAME_LEN] = incremental_name(x);
125126if !ns
127 .address_map
128 .get(&sock_type)
129 .unwrap()
130 .contains_key(&temp_name[..])
131 {
132 name = Some(temp_name.to_vec());
133break;
134 }
135 }
136 }
137138let name = match name {
139Some(x) => x,
140// every valid name has been taken
141None => return Err(BindError::NoNamesAvailable),
142 };
143144let name_copy = name.clone();
145146// when the socket closes, remove this entry from the namespace
147let handle =
148Self::on_socket_close(Arc::downgrade(ns_arc), socket_event_source, move |ns| {
149assert!(ns.unbind(sock_type, &name_copy).is_ok());
150 });
151152if let std::collections::hash_map::Entry::Vacant(entry) = ns
153 .address_map
154 .get_mut(&sock_type)
155 .unwrap()
156 .entry(name.clone())
157 {
158 entry.insert(NamespaceEntry::new(Arc::downgrade(socket), handle));
159 } else {
160unreachable!();
161 }
162163Ok(name)
164 }
165166pub fn unbind(&mut self, sock_type: UnixSocketType, name: &Vec<u8>) -> Result<(), BindError> {
167// remove the namespace entry which includes the handle, so the event listener will
168 // automatically be removed from the socket
169if self
170.address_map
171 .get_mut(&sock_type)
172 .unwrap()
173 .remove(name)
174 .is_none()
175 {
176// didn't exist in the address map
177return Err(BindError::NameNotFound);
178 }
179180Ok(())
181 }
182183/// Adds a listener to the socket which runs the callback `f` when the socket is closed.
184fn on_socket_close(
185 ns: Weak<AtomicRefCell<Self>>,
186 event_source: &mut StateEventSource,
187 f: impl Fn(&mut Self) + Send + Sync + 'static,
188 ) -> StateListenHandle {
189 event_source.add_listener(
190 FileState::CLOSED,
191 FileSignals::empty(),
192 StateListenerFilter::OffToOn,
193move |state, _changed, _signals, _cb_queue| {
194assert!(state.contains(FileState::CLOSED));
195if let Some(ns) = ns.upgrade() {
196 f(&mut ns.borrow_mut());
197 }
198 },
199 )
200 }
201}
202203impl Default for AbstractUnixNamespace {
204fn default() -> Self {
205Self::new()
206 }
207}
208209#[derive(Debug, Clone, Copy)]
210pub enum BindError {
211/// The name is already in use.
212NameInUse,
213/// Names in the ephemeral name range are all in use.
214NoNamesAvailable,
215/// The name was not found in the address map.
216NameNotFound,
217}
218219impl std::error::Error for BindError {}
220221impl std::fmt::Display for BindError {
222fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223match self {
224Self::NameInUse => write!(f, "Name is already in use"),
225Self::NoNamesAvailable => {
226write!(f, "Names in the ephemeral name range are all in use")
227 }
228Self::NameNotFound => write!(f, "Name was not found in the address map"),
229 }
230 }
231}
232233/// The characters that are valid in auto-generated names; see subsection "Autobind feature" in
234/// unix(7).
235const CHARSET: &[u8] = b"abcdef0123456789";
236const NAME_LEN: usize = 5;
237238/// Choose a random name of length `L`.
239fn random_name<const L: usize>(mut rng: impl rand::Rng) -> [u8; L] {
240let mut name = [0u8; L];
241242// set each character of the name
243for c in &mut name {
244*c = *CHARSET.choose(&mut rng).unwrap();
245 }
246247 name
248}
249250/// Get a name in the set of all valid names. This is essentially the n'th element in the cartesian
251/// power of set `CHARSET`. This would be better implemented as a generator when generators become
252/// stable.
253fn incremental_name<const L: usize>(mut index: usize) -> [u8; L] {
254const CHARSET_LEN: usize = CHARSET.len();
255256// there are a limited number of valid names
257assert!(index < CHARSET_LEN.pow(L as u32));
258259let mut name = [0u8; L];
260261// set each character of the name
262for x in 0..L {
263// take the base-10 index and convert it to base-CHARSET_LEN digits
264let charset_index = index % CHARSET_LEN;
265 index /= CHARSET_LEN;
266267// set the name in reverse order
268name[L - x - 1] = CHARSET[charset_index];
269 }
270271 name
272}
273274#[cfg(test)]
275mod tests {
276use rand_core::SeedableRng;
277use rand_xoshiro::Xoshiro256PlusPlus;
278279use super::*;
280281#[test]
282fn test_random_name() {
283let mut rng = Xoshiro256PlusPlus::seed_from_u64(0);
284285let name_1: [u8; 5] = random_name(&mut rng);
286let name_2: [u8; 5] = random_name(&mut rng);
287288assert!(name_1.iter().all(|x| CHARSET.contains(x)));
289assert!(name_2.iter().all(|x| CHARSET.contains(x)));
290assert_ne!(name_1, name_2);
291 }
292293#[test]
294fn test_incremental_name() {
295assert_eq!(incremental_name::<5>(0), [b'a', b'a', b'a', b'a', b'a']);
296assert_eq!(incremental_name::<5>(1), [b'a', b'a', b'a', b'a', b'b']);
297assert_eq!(
298 incremental_name::<5>(CHARSET.len()),
299 [b'a', b'a', b'a', b'b', b'a']
300 );
301assert_eq!(
302 incremental_name::<5>(CHARSET.len() + 1),
303 [b'a', b'a', b'a', b'b', b'b']
304 );
305assert_eq!(
306 incremental_name::<5>(CHARSET.len().pow(5) - 1),
307 [b'9', b'9', b'9', b'9', b'9']
308 );
309 }
310311#[test]
312 #[should_panic]
313fn test_incremental_name_panic() {
314 incremental_name::<5>(CHARSET.len().pow(5));
315 }
316}