Skip to main content

netstack3_tcp/socket/
accept_queue.rs

1// Copyright 2023 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
5//! Defines a thread safe accept queue to be shared between listener and
6//! connected sockets.
7
8use alloc::collections::VecDeque;
9use alloc::sync::Arc;
10#[cfg(test)]
11use alloc::vec::Vec;
12use core::fmt::Debug;
13use core::hash::Hash;
14use core::ops::DerefMut;
15
16use assert_matches::assert_matches;
17use derivative::Derivative;
18use netstack3_base::Inspector;
19use netstack3_base::sync::Mutex;
20use netstack3_hashmap::HashMap;
21
22/// A change that occurred on an [`AcceptQueue`].
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum AcceptQueueChange {
25    /// A pending connection completed the handshake and was added to the queue.
26    ConnectionAdded {
27        /// Whether the accept queue was empty before adding this connection.
28        was_empty: bool,
29    },
30    /// A connection was removed from the queue (via `accept` or reset/close).
31    ConnectionRemoved {
32        /// Whether the queue is now empty after removing this connection.
33        is_empty: bool,
34    },
35}
36
37/// A notifier used to tell Bindings about ready connections for a single
38/// listening socket.
39pub trait ListenerNotifier {
40    /// Called when the accept queue has changed.
41    fn accept_queue_changed(&mut self, change: AcceptQueueChange);
42}
43
44/// A thread-safe shareable accept queue.
45///
46/// [`AcceptQueue`] implements all necessary locking internally and can be
47/// safely shared between a listener and the connected sockets generated from
48/// it.
49#[derive(Debug, Derivative)]
50#[derivative(Clone(bound = ""))]
51pub struct AcceptQueue<S, R, N>(Arc<Mutex<AcceptQueueInner<S, R, N>>>);
52
53#[cfg(test)]
54impl<S, R, N> PartialEq for AcceptQueue<S, R, N>
55where
56    AcceptQueueInner<S, R, N>: PartialEq,
57{
58    fn eq(&self, Self(other): &Self) -> bool {
59        let Self(inner) = self;
60        if Arc::ptr_eq(other, inner) {
61            return true;
62        }
63        let guard = inner.lock();
64        let other_guard = other.lock();
65        (&*guard).eq(&*other_guard)
66    }
67}
68
69#[cfg(test)]
70impl<S, R, N> Eq for AcceptQueue<S, R, N> where Self: PartialEq {}
71
72#[derive(Debug)]
73#[cfg_attr(test, derive(Eq, PartialEq))]
74enum EntryState {
75    Pending,
76    Ready,
77}
78
79#[derive(Debug)]
80#[cfg_attr(test, derive(Derivative))]
81#[cfg_attr(
82    test,
83    derivative(PartialEq(bound = "S: Hash + Clone + Eq + PartialEq, R: PartialEq, N: PartialEq"))
84)]
85struct AcceptQueueInner<S, R, N> {
86    ready_queue: VecDeque<(S, R)>,
87    all_sockets: HashMap<S, EntryState>,
88    notifier: Option<N>,
89}
90
91impl<S, R, N> AcceptQueue<S, R, N>
92where
93    S: Hash + Clone + Eq + PartialEq + Debug,
94    N: ListenerNotifier,
95{
96    /// Creates a new [`AcceptQueue`] with `notifier`.
97    pub(crate) fn new(notifier: N) -> Self {
98        Self(Arc::new(Mutex::new(AcceptQueueInner::new(notifier))))
99    }
100
101    fn lock(&self) -> impl DerefMut<Target = AcceptQueueInner<S, R, N>> + '_ {
102        let Self(inner) = self;
103        inner.lock()
104    }
105
106    /// Pops a ready entry from the queue.
107    ///
108    /// Returns the socket and its associated ready state if the queue was not
109    /// empty.
110    ///
111    /// `pop_ready` also hits the notifier.
112    pub(crate) fn pop_ready(&self) -> Option<(S, R)> {
113        self.lock().pop_ready()
114    }
115
116    /// Collects all currently pending sockets.
117    #[cfg(test)]
118    pub(crate) fn collect_pending(&self) -> Vec<S> {
119        self.lock().collect_pending()
120    }
121
122    /// Pushes a new `pending` connection.
123    ///
124    /// Panics if `pending` is already in the queue or if the queue is already
125    /// closed.
126    pub(crate) fn push_pending(&self, pending: S) {
127        self.lock().push_pending(pending)
128    }
129
130    /// Returns the total number of entries in the queue (pending and ready).
131    pub(crate) fn len(&self) -> usize {
132        self.lock().len()
133    }
134
135    /// Returns the number of ready entries in the queue.
136    #[cfg(test)]
137    pub(crate) fn ready_len(&self) -> usize {
138        self.lock().ready_len()
139    }
140
141    /// Returns the number of pending entries in the queue.
142    #[cfg(test)]
143    pub(crate) fn pending_len(&self) -> usize {
144        self.lock().pending_len()
145    }
146
147    /// Notifies that [`newly_ready`] is now ready to be accepted.
148    ///
149    /// Does nothing if the queue is closed.
150    ///
151    /// Panics if the queue is not closed and `newly_ready` was not in the queue
152    /// as a pending entry.
153    pub(crate) fn notify_ready(&self, newly_ready: &S, ready_state: R) {
154        self.lock().notify_ready(newly_ready, ready_state)
155    }
156
157    /// Removes an entry from the queue.
158    ///
159    /// No-op if the queue is closed or if the entry was not in the queue.
160    pub(crate) fn remove(&self, entry: &S) {
161        self.lock().remove(entry)
162    }
163
164    /// Closes the queue and returns all entries that were in the queue and the
165    /// notifier.
166    ///
167    /// Panics if the queue is already closed.
168    pub(crate) fn close(&self) -> (impl Iterator<Item = S> + use<S, R, N>, N) {
169        self.lock().close()
170    }
171
172    /// Returns true if the queue is closed.
173    pub(crate) fn is_closed(&self) -> bool {
174        self.lock().is_closed()
175    }
176
177    /// Inspects the queue.
178    pub(crate) fn inspect<I: Inspector>(&self, inspector: &mut I) {
179        let inner = self.lock();
180        inspector.record_usize("NumReady", inner.ready_len());
181        inspector.record_usize("NumPending", inner.pending_len());
182        inspector.record_debug("Contents", &inner.all_sockets);
183    }
184}
185
186impl<S, R, N> AcceptQueueInner<S, R, N>
187where
188    S: Hash + Clone + Eq + PartialEq + Debug,
189    N: ListenerNotifier,
190{
191    fn new(notifier: N) -> Self {
192        Self {
193            ready_queue: Default::default(),
194            all_sockets: Default::default(),
195            notifier: Some(notifier),
196        }
197    }
198
199    fn pop_ready(&mut self) -> Option<(S, R)> {
200        let AcceptQueueInner { ready_queue, all_sockets, notifier } = self;
201        let (socket, ready_state) = ready_queue.pop_front()?;
202        // Assert internal consistency on state.
203        assert_matches!(all_sockets.remove(&socket), Some(EntryState::Ready));
204        // Invariant: queue must be empty if notifier is none.
205        let notifier = notifier.as_mut().unwrap();
206        notifier.accept_queue_changed(AcceptQueueChange::ConnectionRemoved {
207            is_empty: ready_queue.is_empty(),
208        });
209        Some((socket, ready_state))
210    }
211
212    #[cfg(test)]
213    pub(crate) fn collect_pending(&self) -> Vec<S> {
214        let AcceptQueueInner { all_sockets, .. } = self;
215        all_sockets
216            .iter()
217            .filter_map(|(socket, state)| match state {
218                EntryState::Ready => None,
219                EntryState::Pending => Some(socket.clone()),
220            })
221            .collect()
222    }
223
224    fn push_pending(&mut self, pending: S) {
225        let AcceptQueueInner { all_sockets, notifier, .. } = self;
226        // Protect against the listener attempting to push pending
227        // connections if the queue is closed.
228        assert!(notifier.is_some());
229        assert_matches!(all_sockets.insert(pending, EntryState::Pending), None);
230    }
231
232    fn len(&self) -> usize {
233        let AcceptQueueInner { all_sockets, .. } = self;
234        all_sockets.len()
235    }
236
237    fn ready_len(&self) -> usize {
238        let AcceptQueueInner { ready_queue, .. } = self;
239        ready_queue.len()
240    }
241
242    fn pending_len(&self) -> usize {
243        let AcceptQueueInner { ready_queue, all_sockets, .. } = self;
244        all_sockets.len() - ready_queue.len()
245    }
246
247    fn notify_ready(&mut self, newly_ready: &S, ready_state: R) {
248        let AcceptQueueInner { ready_queue, all_sockets, notifier } = self;
249        let notifier = match notifier {
250            Some(notifier) => notifier,
251
252            None => {
253                // Queue is closed, listener must be shutting down.
254                // Maintain the invariant that a closed queue has cleared all
255                // its entries.
256                debug_assert!(ready_queue.is_empty());
257                debug_assert!(all_sockets.is_empty());
258                return;
259            }
260        };
261        let entry = all_sockets
262            .get_mut(newly_ready)
263            .expect("attempted to notify ready entry that was not in queue");
264        let prev_state = core::mem::replace(entry, EntryState::Ready);
265        assert_matches!(prev_state, EntryState::Pending);
266        let was_empty = ready_queue.is_empty();
267        ready_queue.push_back((newly_ready.clone(), ready_state));
268        notifier.accept_queue_changed(AcceptQueueChange::ConnectionAdded { was_empty });
269    }
270
271    fn remove(&mut self, entry: &S) {
272        let AcceptQueueInner { ready_queue, all_sockets, notifier } = self;
273        // Avoid a HashMap lookup if the queue is already closed.
274        let notifier = match notifier.as_mut() {
275            Some(notifier) => notifier,
276            None => {
277                // Maintain the invariant that a closed queue has cleared all
278                // its entries.
279                debug_assert!(ready_queue.is_empty());
280                debug_assert!(all_sockets.is_empty());
281                return;
282            }
283        };
284
285        match all_sockets.remove(entry) {
286            Some(EntryState::Pending) | None => (),
287            Some(EntryState::Ready) => {
288                let before_len = ready_queue.len();
289                ready_queue.retain(|(s, _ready_data)| s != entry);
290                let after_len = ready_queue.len();
291                // Item must only be in ready queue once.
292                assert_eq!(after_len, before_len - 1);
293                notifier.accept_queue_changed(AcceptQueueChange::ConnectionRemoved {
294                    is_empty: ready_queue.is_empty(),
295                });
296            }
297        }
298    }
299
300    fn close(&mut self) -> (impl Iterator<Item = S> + use<S, R, N>, N) {
301        let AcceptQueueInner { ready_queue, all_sockets, notifier } = self;
302        // Remove the notifier, this signals that the queue is closed.
303        let notifier = notifier.take().expect("queue is already closed");
304        // Remove all items from the ready queue by replacing it with an empty
305        // VecDeque. This ensures that it'll immediately free all of its memory
306        // as opposed to just calling clear.
307        *ready_queue = Default::default();
308        // Take all the entries so we can return from the caller, leaving a
309        // fresh empty HashMap in its place.
310        let entries = core::mem::take(all_sockets);
311        (entries.into_keys(), notifier)
312    }
313
314    fn is_closed(&self) -> bool {
315        let AcceptQueueInner { notifier, .. } = self;
316        notifier.is_none()
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use assert_matches::assert_matches;
323    use netstack3_hashmap::HashSet;
324
325    use super::AcceptQueueChange;
326
327    #[test]
328    fn push_ready_pop() {
329        let mut queue = AcceptQueueInner::new(Notifier::default());
330        assert_eq!(queue.pop_ready(), None);
331        assert_eq!(queue.len(), 0);
332        assert_eq!(queue.ready_len(), 0);
333        assert_eq!(queue.pending_len(), 0);
334        assert_eq!(queue.clear_notifier(), None);
335
336        queue.push_pending(Socket(0));
337        assert_eq!(queue.pop_ready(), None);
338        assert_eq!(queue.len(), 1);
339        assert_eq!(queue.ready_len(), 0);
340        assert_eq!(queue.pending_len(), 1);
341        assert_eq!(queue.clear_notifier(), None);
342
343        queue.notify_ready(&Socket(0), Ready(2));
344        assert_eq!(queue.len(), 1);
345        assert_eq!(queue.ready_len(), 1);
346        assert_eq!(queue.pending_len(), 0);
347        assert_eq!(
348            queue.clear_notifier(),
349            Some(AcceptQueueChange::ConnectionAdded { was_empty: true })
350        );
351
352        queue.push_pending(Socket(1));
353        queue.notify_ready(&Socket(1), Ready(3));
354        assert_eq!(queue.len(), 2);
355        assert_eq!(queue.ready_len(), 2);
356        assert_eq!(queue.pending_len(), 0);
357        assert_eq!(
358            queue.clear_notifier(),
359            Some(AcceptQueueChange::ConnectionAdded { was_empty: false })
360        );
361
362        assert_eq!(queue.pop_ready(), Some((Socket(0), Ready(2))));
363        assert_eq!(
364            queue.clear_notifier(),
365            Some(AcceptQueueChange::ConnectionRemoved { is_empty: false })
366        );
367        assert_eq!(queue.len(), 1);
368        assert_eq!(queue.ready_len(), 1);
369        assert_eq!(queue.pending_len(), 0);
370
371        assert_eq!(queue.pop_ready(), Some((Socket(1), Ready(3))));
372        assert_eq!(
373            queue.clear_notifier(),
374            Some(AcceptQueueChange::ConnectionRemoved { is_empty: true })
375        );
376        assert_eq!(queue.len(), 0);
377        assert_eq!(queue.ready_len(), 0);
378        assert_eq!(queue.pending_len(), 0);
379        assert_eq!(queue.pop_ready(), None);
380    }
381
382    #[test]
383    fn close() {
384        let mut queue = AcceptQueueInner::new(Notifier::default());
385        let mut expect = HashSet::new();
386        for i in 0..3 {
387            let s = Socket(i);
388            queue.push_pending(s.clone());
389            assert!(expect.insert(s));
390        }
391        let (socks, _notifier) = queue.close();
392        let got = socks.collect::<HashSet<_>>();
393        assert_eq!(got, expect);
394
395        assert!(queue.is_closed());
396        assert_eq!(queue.len(), 0);
397    }
398
399    #[test]
400    fn remove() {
401        let mut queue = AcceptQueueInner::new(Notifier::default());
402        let s1 = Socket(1);
403        let s2 = Socket(2);
404        queue.push_pending(s1.clone());
405        queue.push_pending(s2.clone());
406        queue.notify_ready(&s2, Ready(2));
407        assert_eq!(queue.len(), 2);
408        assert_eq!(queue.ready_len(), 1);
409        assert_eq!(queue.pending_len(), 1);
410        assert_eq!(
411            queue.clear_notifier(),
412            Some(AcceptQueueChange::ConnectionAdded { was_empty: true })
413        );
414
415        queue.remove(&s1);
416        assert_eq!(queue.len(), 1);
417        assert_eq!(queue.ready_len(), 1);
418        assert_eq!(queue.pending_len(), 0);
419        assert_eq!(queue.clear_notifier(), None);
420
421        queue.remove(&s2);
422        assert_eq!(queue.len(), 0);
423        assert_eq!(queue.ready_len(), 0);
424        assert_eq!(queue.pending_len(), 0);
425        assert_eq!(
426            queue.clear_notifier(),
427            Some(AcceptQueueChange::ConnectionRemoved { is_empty: true })
428        );
429
430        // Removing already removed entry is a no-op.
431        queue.remove(&s1);
432        queue.remove(&s2);
433        assert_eq!(queue.len(), 0);
434        assert_eq!(queue.ready_len(), 0);
435        assert_eq!(queue.pending_len(), 0);
436        assert_eq!(queue.clear_notifier(), None);
437    }
438
439    #[derive(Default, Eq, PartialEq, Debug, Hash, Clone)]
440    struct Socket(usize);
441    #[derive(Default, Eq, PartialEq, Debug)]
442    struct Ready(usize);
443
444    #[derive(Default, Eq, PartialEq, Debug)]
445    struct Notifier(Option<AcceptQueueChange>);
446
447    type AcceptQueueInner = super::AcceptQueueInner<Socket, Ready, Notifier>;
448
449    impl AcceptQueueInner {
450        fn clear_notifier(&mut self) -> Option<AcceptQueueChange> {
451            let Self { notifier, .. } = self;
452            let Notifier(v) = notifier.as_mut().unwrap();
453            v.take()
454        }
455    }
456
457    impl super::ListenerNotifier for Notifier {
458        fn accept_queue_changed(&mut self, change: AcceptQueueChange) {
459            let Self(n) = self;
460            assert_matches!(n.replace(change), None);
461        }
462    }
463}