tor_guardmgr/
pending.rs

1//! Help the guard manager (and other crates) deal with "pending
2//! information".
3//!
4//! There are two kinds of pending information to deal with.  First,
5//! every guard that we hand out needs to be marked as succeeded or
6//! failed. Second, if a guard is given out on an exploratory basis,
7//! then the circuit manager can't know whether to use a circuit built
8//! through that guard until the guard manager tells it.  This is
9//! handled via [`GuardUsable`].
10use crate::{daemon, FirstHopId};
11
12use educe::Educe;
13use futures::{channel::mpsc::UnboundedSender, Future};
14use oneshot_fused_workaround as oneshot;
15use pin_project::pin_project;
16use std::fmt::Debug;
17use std::pin::Pin;
18use std::sync::atomic::{AtomicU64, Ordering};
19use std::task::{Context, Poll};
20use std::time::Instant;
21use tor_proto::ClockSkew;
22
23use tor_basic_utils::skip_fmt;
24
25/// A future used to see if we have "permission" to use a guard.
26///
27/// For efficiency, the [`GuardMgr`](crate::GuardMgr) implementation sometimes gives
28/// out lower-priority guards when it is not certain whether
29/// higher-priority guards are running.  After having built a circuit
30/// with such a guard, the caller must wait on this future to see whether
31/// the circuit is usable or not.
32///
33/// The circuit may be usable immediately (as happens if the guard was
34/// of sufficient priority, or if all higher-priority guards are
35/// _known_ to be down).  It may eventually _become_ usable (if all of
36/// the higher-priority guards are _discovered_ to be down).  Or it may
37/// eventually become unusable (if we find a higher-priority guard
38/// that works).
39///
40/// Any [`GuardRestriction`](crate::GuardRestriction)s that were used to select this guard
41/// may influence whether it is usable: if higher priority guards were
42/// ignored because of a restriction, then we might use a guard that we
43/// otherwise wouldn't.
44#[pin_project]
45pub struct GuardUsable {
46    /// If present, then this is a future to wait on to see whether the
47    /// guard is usable.
48    ///
49    /// If absent, then the guard is ready immediately and no waiting
50    /// is needed.
51    //
52    // TODO: use a type that makes the case here more distinguishable.
53    #[pin]
54    u: Option<oneshot::Receiver<bool>>,
55}
56
57impl Future for GuardUsable {
58    type Output = Result<bool, oneshot::Canceled>;
59
60    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
61        match self.project().u.as_pin_mut() {
62            None => Poll::Ready(Ok(true)),
63            Some(u) => u.poll(cx),
64        }
65    }
66}
67
68impl GuardUsable {
69    /// Create a new GuardUsable for a primary guard or a fallback directory.
70    ///
71    /// (Circuits built through these are usable immediately, independently of
72    /// whether other guards succeed or fail, so we don't need a way to report
73    /// whether such guards/fallbacks are usable.)
74    pub(crate) fn new_usable_immediately() -> Self {
75        GuardUsable { u: None }
76    }
77
78    /// Create a new GuardUsable for a guard with undecided usability status.
79    ///
80    /// (We use this constructor when a circuit is built through a non-primary
81    /// guard, and there are other guards _we would prefer to use, if they turn
82    /// out to work_.  If such a circuit succeeds, the caller must still use
83    /// this `GuardUsable` to wait until the `GuardMgr` sees whether the
84    /// more-preferred guards have succeeded or failed.)
85    pub(crate) fn new_uncertain() -> (Self, oneshot::Sender<bool>) {
86        let (snd, rcv) = oneshot::channel();
87        (GuardUsable { u: Some(rcv) }, snd)
88    }
89}
90
91/// A message that we can get back from the circuit manager who asked
92/// for a guard.
93#[derive(Copy, Clone, Debug)]
94#[non_exhaustive]
95pub enum GuardStatus {
96    /// The guard was used successfully.
97    Success,
98    /// The guard was used unsuccessfully.
99    Failure,
100    /// The circuit failed in a way that we cannot prove is the guard's
101    /// fault, but which _might_ be the guard's fault.
102    Indeterminate,
103    /// Our attempt to use the guard didn't get far enough to be sure
104    /// whether the guard is usable or not.
105    AttemptAbandoned,
106}
107
108/// An object used to tell the [`GuardMgr`](crate::GuardMgr) about the result of
109/// trying to build a circuit through a guard.
110///
111/// The `GuardMgr` needs to know about these statuses, so that it can tell
112/// whether the guard is running or not.
113#[must_use = "You need to report the status of any guard that you asked for"]
114#[derive(Educe)]
115#[educe(Debug)]
116pub struct GuardMonitor {
117    /// The Id that we're going to report about.
118    id: RequestId,
119    /// The status that we will report if this monitor is dropped now.
120    pending_status: GuardStatus,
121    /// If set, we change `Indeterminate` to `AttemptAbandoned` before
122    /// reporting it to the guard manager.
123    ///
124    /// We do this when a failure to finish the circuit doesn't reflect
125    /// badly against the guard at all: typically, because the circuit's
126    /// path is not random.
127    ignore_indeterminate: bool,
128    /// If set, we will report the given clock skew as having been observed and
129    /// authenticated from this guard or fallback.
130    pending_skew: Option<ClockSkew>,
131    /// A sender that needs to get told when the attempt to use the guard is
132    /// finished or abandoned.
133    ///
134    /// TODO: This doesn't really need to be an Option, but we use None
135    /// here to indicate that we've already used the sender, and it can't
136    /// be used again.
137    #[educe(Debug(method = "skip_fmt"))]
138    snd: Option<UnboundedSender<daemon::Msg>>,
139}
140
141impl GuardMonitor {
142    /// Create a new GuardMonitor object.
143    pub(crate) fn new(id: RequestId, snd: UnboundedSender<daemon::Msg>) -> Self {
144        GuardMonitor {
145            id,
146            pending_status: GuardStatus::AttemptAbandoned,
147            ignore_indeterminate: false,
148            pending_skew: None,
149            snd: Some(snd),
150        }
151    }
152
153    /// Report that a circuit was successfully built in a way that
154    /// indicates that the guard is working.
155    ///
156    /// Note that this doesn't necessarily mean that the circuit
157    /// succeeded. For example, we might decide that extending to a
158    /// second hop means that a guard is usable, even if the circuit
159    /// stalled at the third hop.
160    pub fn succeeded(self) {
161        self.report(GuardStatus::Success);
162    }
163
164    /// Report that the circuit could not be built successfully, in
165    /// a way that indicates that the guard isn't working.
166    ///
167    /// (This either be because of a network failure, a timeout, or
168    /// something else.)
169    pub fn failed(self) {
170        self.report(GuardStatus::Failure);
171    }
172
173    /// Report that we did not try to build a circuit using the guard,
174    /// or that we can't tell whether the guard is working.
175    ///
176    /// Dropping a `GuardMonitor` is without calling `succeeded` or
177    /// `failed` or `pending_status` is equivalent to calling this
178    /// function.
179    pub fn attempt_abandoned(self) {
180        self.report(GuardStatus::AttemptAbandoned);
181    }
182
183    /// Configure this monitor so that, if it is dropped before use,
184    /// it sends the status `status`.
185    pub fn pending_status(&mut self, status: GuardStatus) {
186        self.pending_status = status;
187    }
188
189    /// Set the given clock skew value to be reported to the guard manager.
190    ///
191    /// Clock skew can be reported on success or failure, but it should only be
192    /// reported if the first hop is actually authenticated.
193    pub fn skew(&mut self, skew: ClockSkew) {
194        self.pending_skew = Some(skew);
195    }
196
197    /// Return the current pending status and "ignore indeterminate"
198    /// status for this guard monitor.
199    #[cfg(feature = "testing")]
200    pub fn inspect_pending_status(&self) -> (GuardStatus, bool) {
201        (self.pending_status, self.ignore_indeterminate)
202    }
203
204    /// Configure this monitor to ignore any indeterminate status
205    /// values, and treat them as abandoned attempts.
206    ///
207    /// We should use this whenever the path being built with this guard
208    /// is not randomly generated.
209    pub fn ignore_indeterminate_status(&mut self) {
210        self.ignore_indeterminate = true;
211    }
212
213    /// Report a message for this guard.
214    pub fn report(mut self, msg: GuardStatus) {
215        self.report_impl(msg);
216    }
217
218    /// As [`GuardMonitor::report`], but take a &mut reference.
219    fn report_impl(&mut self, msg: GuardStatus) {
220        let msg = match (msg, self.ignore_indeterminate) {
221            (GuardStatus::Indeterminate, true) => GuardStatus::AttemptAbandoned,
222            (m, _) => m,
223        };
224        let _ignore = self
225            .snd
226            .take()
227            .expect("GuardMonitor initialized with no sender")
228            .unbounded_send(daemon::Msg::Status(self.id, msg, self.pending_skew));
229    }
230
231    /// Report the pending message for his guard, whatever it is.
232    pub fn commit(self) {
233        let status = self.pending_status;
234        self.report(status);
235    }
236}
237
238impl Drop for GuardMonitor {
239    fn drop(&mut self) {
240        if self.snd.is_some() {
241            self.report_impl(self.pending_status);
242        }
243    }
244}
245
246/// Internal unique identifier used to tell PendingRequest objects apart.
247#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
248pub(crate) struct RequestId {
249    /// The value of the identifier.
250    id: u64,
251}
252
253impl RequestId {
254    /// Create a new, never-before-used RequestId.
255    ///
256    /// # Panics
257    ///
258    /// Panics if we have somehow exhausted a 64-bit space of request IDs.
259    pub(crate) fn next() -> RequestId {
260        /// The next identifier in sequence we'll give out.
261        static NEXT_VAL: AtomicU64 = AtomicU64::new(1);
262        let id = NEXT_VAL.fetch_add(1, Ordering::Relaxed);
263        assert!(id != 0, "Exhausted guard request Id space.");
264        RequestId { id }
265    }
266}
267
268/// Pending information about a guard that we handed out in response to
269/// some request, but where we have not yet reported whether the guard
270/// is usable.
271///
272/// We create one of these whenever we give out a guard with an
273/// uncertain usability status via [`GuardUsable::new_uncertain`].
274#[derive(Debug)]
275pub(crate) struct PendingRequest {
276    /// Identity of the guard that we gave out.
277    guard_id: FirstHopId,
278    /// The usage for which this guard was requested.
279    ///
280    /// We need this information because, if we find that a better guard
281    /// than this one might be usable, we should only give it precedence
282    /// if that guard is also allowable _for this usage_.
283    usage: crate::GuardUsage,
284    /// A oneshot channel used to tell the circuit manager that a circuit
285    /// built through this guard can be used.
286    ///
287    /// (This is an option so that we can safely make reply() once-only.
288    /// Otherwise we run into lifetime issues elsewhere.)
289    usable: Option<oneshot::Sender<bool>>,
290    /// The time at which the circuit manager told us that this guard was
291    /// successful.
292    waiting_since: Option<Instant>,
293    /// If true, then the network has been down for a long time when we
294    /// launched this request.
295    ///
296    /// If this request succeeds, it probably means that the net has
297    /// come back up.
298    net_has_been_down: bool,
299}
300
301impl PendingRequest {
302    /// Create a new PendingRequest.
303    pub(crate) fn new(
304        guard_id: FirstHopId,
305        usage: crate::GuardUsage,
306        usable: Option<oneshot::Sender<bool>>,
307        net_has_been_down: bool,
308    ) -> Self {
309        PendingRequest {
310            guard_id,
311            usage,
312            usable,
313            waiting_since: None,
314            net_has_been_down,
315        }
316    }
317
318    /// Return the Id of the guard we gave out.
319    pub(crate) fn guard_id(&self) -> &FirstHopId {
320        &self.guard_id
321    }
322
323    /// Return the usage for which we gave out the guard.
324    pub(crate) fn usage(&self) -> &crate::GuardUsage {
325        &self.usage
326    }
327
328    /// Return the time (if any) when we were told that the guard
329    /// was successful.
330    pub(crate) fn waiting_since(&self) -> Option<Instant> {
331        self.waiting_since
332    }
333
334    /// Return true if the network had been down for a long time when
335    /// this guard was handed out.
336    pub(crate) fn net_has_been_down(&self) -> bool {
337        self.net_has_been_down
338    }
339
340    /// Tell the circuit manager that the guard is usable (or unusable),
341    /// depending on the argument.
342    ///
343    /// Does nothing if reply() has already been called.
344    pub(crate) fn reply(&mut self, usable: bool) {
345        if let Some(sender) = self.usable.take() {
346            // If this gives us an error, then the circuit manager doesn't
347            // care about this circuit any more.
348            let _ignore = sender.send(usable);
349        }
350    }
351
352    /// Mark this request as "waiting" since the time `now`.
353    ///
354    /// This function should only be called once per request.
355    pub(crate) fn mark_waiting(&mut self, now: Instant) {
356        debug_assert!(self.waiting_since.is_none());
357        self.waiting_since = Some(now);
358    }
359}