//! Help the guard manager (and other crates) deal with "pending //! information". //! //! There are two kinds of pending information to deal with. First, //! every guard that we hand out needs to be marked as succeeded or //! failed. Second, if a guard is given out on an exploratory basis, //! then the circuit manager can't know whether to use a circuit built //! through that guard until the guard manager tells it. This is //! handled via [`GuardUsable`]. use crate::{daemon, GuardId}; use futures::{ channel::{mpsc::UnboundedSender, oneshot}, Future, }; use pin_project::pin_project; use std::fmt::{self, Debug}; use std::pin::Pin; use std::sync::atomic::{AtomicU64, Ordering}; use std::task::{Context, Poll}; use std::time::Instant; /// A future used to see if we have "permission" to use a guard. /// /// For efficiency, the [`GuardMgr`](crate::GuardMgr) implementation sometimes gives /// out lower-priority guards when it is not certain whether /// higher-priority guards are running. After having built a circuit /// with such a guard, the caller must wait on this future to see whether /// the circuit is usable or not. /// /// The circuit may be usable immediately (as happens if the guard was /// of sufficient priority, or if all higher-priority guards are /// _known_ to be down). It may eventually _become_ usable (if all of /// the higher-priority guards are _discovered_ to be down). Or it may /// eventually become unusable (if we find a higher-priority guard /// that works). /// /// Any [`GuardRestriction`](crate::GuardRestriction)s that were used to select this guard /// may influence whether it is usable: if higher priority guards were /// ignored because of a restriction, then we might use a guard that we /// otherwise wouldn't. #[pin_project] pub struct GuardUsable { /// If present, then this is a future to wait on to see whether the /// guard is usable. /// /// If absent, then the guard is ready immediately and no waiting /// is needed. #[pin] u: Option>, } impl Future for GuardUsable { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { match self.project().u.as_pin_mut() { None => Poll::Ready(Ok(true)), Some(u) => u.poll(cx), } } } impl GuardUsable { /// Create a new GuardUsable for a primary guard. /// /// (Circuits built through primary guards are usable immediately, /// so we don't need a way to report that this guard is usable.) pub(crate) fn new_primary() -> Self { GuardUsable { u: None } } /// Create a new GuardUsable for a guard with undecided usability /// status. pub(crate) fn new_uncertain() -> (Self, oneshot::Sender) { let (snd, rcv) = oneshot::channel(); (GuardUsable { u: Some(rcv) }, snd) } } /// A message that we can get back from the circuit manager who asked /// for a guard. #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub enum GuardStatus { /// The guard was used successfully. Success, /// The guard was used unsuccessfully. Failure, /// The circuit failed in a way that we cannot prove is the guard's /// fault, but which _might_ be the guard's fault. Indeterminate, /// Our attempt to use the guard didn't get far enough to be sure /// whether the guard is usable or not. AttemptAbandoned, } /// An object used to tell the [`GuardMgr`](crate::GuardMgr) about the result of /// trying to build a circuit through a guard. /// /// The `GuardMgr` needs to know about these statuses, so that it can tell /// whether the guard is running or not. #[must_use = "You need to report the status of any guard that you asked for"] pub struct GuardMonitor { /// The Id that we're going to report about. id: RequestId, /// The status that we will report if this monitor is dropped now. pending_status: GuardStatus, /// If set, we change `Indeterminate` to `AttemptAbandoned` before /// reporting it to the guard manager. /// /// We do this when a failure to finish the circuit doesn't reflect /// badly against the guard at all: typically, because the circuit's /// path is not random. ignore_indeterminate: bool, /// A sender that needs to get told when the attempt to use the guard is /// finished or abandoned. /// /// TODO: This doesn't really need to be an Option, but we use None /// here to indicate that we've already used the sender, and it can't /// be used again. snd: Option>, } impl Debug for GuardMonitor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("GuardMonitor") .field("id", &self.id) .field("pending_status", &self.pending_status) .field("ignore_indeterminate", &self.ignore_indeterminate) .finish_non_exhaustive() } } impl GuardMonitor { /// Create a new GuardMonitor object. pub(crate) fn new(id: RequestId, snd: UnboundedSender) -> Self { GuardMonitor { id, pending_status: GuardStatus::AttemptAbandoned, ignore_indeterminate: false, snd: Some(snd), } } /// Report that a circuit was successfully built in a way that /// indicates that the guard is working. /// /// Note that this doesn't necessarily mean that the circuit /// succeeded. For example, we might decide that extending to a /// second hop means that a guard is usable, even if the circuit /// stalled at the third hop. pub fn succeeded(self) { self.report(GuardStatus::Success); } /// Report that the circuit could not be built successfully, in /// a way that indicates that the guard isn't working. /// /// (This either be because of a network failure, a timeout, or /// something else.) pub fn failed(self) { self.report(GuardStatus::Failure); } /// Report that we did not try to build a circuit using the guard, /// or that we can't tell whether the guard is working. /// /// Dropping a `GuardMonitor` is without calling `succeeded` or /// `failed` or `pending_status` is equivalent to calling this /// function. pub fn attempt_abandoned(self) { self.report(GuardStatus::AttemptAbandoned); } /// Configure this monitor so that, if it is dropped before use, /// it sends the status `status`. pub fn pending_status(&mut self, status: GuardStatus) { self.pending_status = status; } /// Return the current pending status and "ignore indeterminate" /// status for this guard monitor. #[cfg(feature = "testing")] pub fn inspect_pending_status(&self) -> (GuardStatus, bool) { (self.pending_status, self.ignore_indeterminate) } /// Configure this monitor to ignore any indeterminate status /// values, and treat them as abandoned attempts. /// /// We should use this whenever the path being built with this guard /// is not randomly generated. pub fn ignore_indeterminate_status(&mut self) { self.ignore_indeterminate = true; } /// Report a message for this guard. pub fn report(mut self, msg: GuardStatus) { self.report_impl(msg); } /// As [`GuardMonitor::report`], but take a &mut reference. fn report_impl(&mut self, msg: GuardStatus) { let msg = match (msg, self.ignore_indeterminate) { (GuardStatus::Indeterminate, true) => GuardStatus::AttemptAbandoned, (m, _) => m, }; let _ignore = self .snd .take() .expect("GuardMonitor initialized with no sender") .unbounded_send(daemon::Msg::Status(self.id, msg)); } /// Report the pending message for his guard, whatever it is. pub fn commit(self) { let status = self.pending_status; self.report(status); } } impl Drop for GuardMonitor { fn drop(&mut self) { if self.snd.is_some() { self.report_impl(self.pending_status); } } } /// Internal unique identifier used to tell PendingRequest objects apart. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub(crate) struct RequestId { /// The value of the identifier. id: u64, } impl RequestId { /// Create a new, never-before-used RequestId. /// /// # Panics /// /// Panics if we have somehow exhausted a 64-bit space of request IDs. pub(crate) fn next() -> RequestId { /// The next identifier in sequence we'll give out. static NEXT_VAL: AtomicU64 = AtomicU64::new(1); let id = NEXT_VAL.fetch_add(1, Ordering::Relaxed); assert!(id != 0, "Exhausted guard request Id space."); RequestId { id } } } /// Pending information about a guard that we handed out in response to /// some request, but where we have not yet reported whether the guard /// is usable. /// /// We create one of these whenever we give out a guard with an /// uncertain usability status via [`GuardUsable::new_uncertain`]. #[derive(Debug)] pub(crate) struct PendingRequest { /// Identity of the guard that we gave out. guard_id: GuardId, /// The usage for which this guard was requested. /// /// We need this information because, if we find that a better guard /// than this one might be usable, we should only give it precedence /// if that guard is also allowable _for this usage_. usage: crate::GuardUsage, /// A oneshot channel used to tell the circuit manager that a circuit /// built through this guard can be used. /// /// (This is an option so that we can safely make reply() once-only. /// Otherwise we run into lifetime issues elsewhere.) usable: Option>, /// The time at which the circuit manager told us that this guard was /// successful. waiting_since: Option, /// If true, then the network has been down for a long time when we /// launched this request. /// /// If this request succeeds, it probably means that the net has /// come back up. net_has_been_down: bool, } impl PendingRequest { /// Create a new PendingRequest. pub(crate) fn new( guard_id: GuardId, usage: crate::GuardUsage, usable: Option>, net_has_been_down: bool, ) -> Self { PendingRequest { guard_id, usage, usable, waiting_since: None, net_has_been_down, } } /// Return the Id of the guard we gave out. pub(crate) fn guard_id(&self) -> &GuardId { &self.guard_id } /// Return the usage for which we gave out the guard. pub(crate) fn usage(&self) -> &crate::GuardUsage { &self.usage } /// Return the time (if any) when we were told that the guard /// was successful. pub(crate) fn waiting_since(&self) -> Option { self.waiting_since } /// Return true if the network had been down for a long time when /// this guard was handed out. pub(crate) fn net_has_been_down(&self) -> bool { self.net_has_been_down } /// Tell the circuit manager that the guard is usable (or unusable), /// depending on the argument. /// /// Does nothing if reply() has already been called. pub(crate) fn reply(&mut self, usable: bool) { if let Some(sender) = self.usable.take() { // If this gives us an error, then the circuit manager doesn't // care about this circuit any more. let _ignore = sender.send(usable); } } /// Mark this request as "waiting" since the time `now`. /// /// This function should only be called once per request. pub(crate) fn mark_waiting(&mut self, now: Instant) { debug_assert!(self.waiting_since.is_none()); self.waiting_since = Some(now); } }