1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
//! 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, FirstHopId};
use educe::Educe;
use futures::{
channel::{mpsc::UnboundedSender, oneshot},
Future,
};
use pin_project::pin_project;
use std::fmt::Debug;
use std::pin::Pin;
use std::sync::atomic::{AtomicU64, Ordering};
use std::task::{Context, Poll};
use std::time::Instant;
use tor_proto::ClockSkew;
use tor_basic_utils::skip_fmt;
/// 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.
//
// TODO: use a type that makes the case here more distinguishable.
#[pin]
u: Option<oneshot::Receiver<bool>>,
}
impl Future for GuardUsable {
type Output = Result<bool, oneshot::Canceled>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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 or a fallback directory.
///
/// (Circuits built through these are usable immediately, independently of
/// whether other guards succeed or fail, so we don't need a way to report
/// whether such guards/fallbacks are usable.)
pub(crate) fn new_usable_immediately() -> Self {
GuardUsable { u: None }
}
/// Create a new GuardUsable for a guard with undecided usability status.
///
/// (We use this constructor when a circuit is built through a non-primary
/// guard, and there are other guards _we would prefer to use, if they turn
/// out to work_. If such a circuit succeeds, the caller must still use
/// this `GuardUsable` to wait until the `GuardMgr` sees whether the
/// more-preferred guards have succeeded or failed.)
pub(crate) fn new_uncertain() -> (Self, oneshot::Sender<bool>) {
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"]
#[derive(Educe)]
#[educe(Debug)]
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,
/// If set, we will report the given clock skew as having been observed and
/// authenticated from this guard or fallback.
pending_skew: Option<ClockSkew>,
/// 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.
#[educe(Debug(method = "skip_fmt"))]
snd: Option<UnboundedSender<daemon::Msg>>,
}
impl GuardMonitor {
/// Create a new GuardMonitor object.
pub(crate) fn new(id: RequestId, snd: UnboundedSender<daemon::Msg>) -> Self {
GuardMonitor {
id,
pending_status: GuardStatus::AttemptAbandoned,
ignore_indeterminate: false,
pending_skew: None,
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;
}
/// Set the given clock skew value to be reported to the guard manager.
///
/// Clock skew can be reported on success or failure, but it should only be
/// reported if the first hop is actually authenticated.
pub fn skew(&mut self, skew: ClockSkew) {
self.pending_skew = Some(skew);
}
/// 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, self.pending_skew));
}
/// 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: FirstHopId,
/// 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<oneshot::Sender<bool>>,
/// The time at which the circuit manager told us that this guard was
/// successful.
waiting_since: Option<Instant>,
/// 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: FirstHopId,
usage: crate::GuardUsage,
usable: Option<oneshot::Sender<bool>>,
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) -> &FirstHopId {
&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<Instant> {
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);
}
}