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}