tor_ptmgr/err.rs
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
//! Errors to do with pluggable transports.
use fs_mistrust::anon_home::PathExt as _;
use futures::task::SpawnError;
use std::path::PathBuf;
use std::sync::Arc;
use tor_chanmgr::factory::AbstractPtError;
use tor_config::{CfgPath, CfgPathError};
use tor_error::{ErrorKind, HasKind, HasRetryTime, RetryTime};
/// An error spawning or managing a pluggable transport.
#[derive(Clone, Debug, thiserror::Error)]
#[non_exhaustive]
pub enum PtError {
/// We failed to launch a set of pluggable transports in the provided deadline.
#[error("PT launch timed out")]
Timeout,
/// A PT binary does not support a set of pluggable transports.
#[error("PT binary does not support transports: {0:?}")]
ClientTransportsUnsupported(Vec<String>),
/// A PT binary failed to launch a pluggable transport, and reported
/// an error message.
#[error("Transport '{}' failed to launch, saying: {:?}", transport, message)]
TransportGaveError {
/// The transport that failed.
transport: String,
/// The failure message.
message: String,
},
/// A pluggable transport binary failed to understand us.
#[error("PT reported protocol error: {0}")]
ChildProtocolViolation(String),
/// A pluggable transport binary violated the protocol.
#[error("PT violated protocol: {0}")]
ProtocolViolation(String),
/// A pluggable transport binary doesn't support version 1 of the IPC protocol.
#[error("PT binary uses unsupported protocol version")]
UnsupportedVersion,
/// A pluggable transport binary couldn't use the provided proxy URI.
#[error("PT binary failed to use proxy URI: {0}")]
ProxyError(String),
/// A pluggable transport binary quit or was stopped.
#[error("PT binary gone")]
ChildGone,
/// An error was encountered communicating with a pluggable transport binary. The PT is no
/// longer usable.
#[error("Failed to read from PT binary: {0}")]
ChildReadFailed(Arc<std::io::Error>),
/// We couldn't spawn a pluggable transport binary as a child process.
#[error("Couldn't execute PT binary at {}: {}", path.anonymize_home(), error)]
ChildSpawnFailed {
/// The binary path we tried to execute.
path: PathBuf,
/// The I/O error returned.
#[source]
error: Arc<std::io::Error>,
},
/// We failed to parse something a pluggable transport sent us.
#[error("Couldn't parse IPC line \"{}\": {}", line, error)]
IpcParseFailed {
/// The offending line.
line: String,
/// The error encountered parsing it.
error: String,
},
/// We couldn't create a state directory.
#[error("Failed to create a state directory at {}: {}", path.anonymize_home(), error)]
StatedirCreateFailed {
/// The offending path.
path: PathBuf,
/// The error encountered.
#[source]
error: Arc<std::io::Error>,
},
/// We couldn't expand a path.
#[error("Failed to expand path {}: {}", path, error)]
PathExpansionFailed {
/// The offending path.
path: CfgPath,
/// The error encountered.
#[source]
error: CfgPathError,
},
/// A binary path does not have the syntax of a *file* name.
///
/// For example, it ends in a slash, indicating a directory.
//
// TODO: this should be rejected at the configuration parsing level, and treated as a bug here.
#[error("Configured binary path {} doesn't have syntax of a file", path.anonymize_home())]
NotAFile {
/// The offending path.
path: PathBuf,
},
/// Unable to spawn reactor task.
#[error("Unable to spawn reactor task.")]
Spawn {
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
/// The requested transport was found to be missing due to racing with reconfiguration
#[error("Transport not found due to concurrent reconfiguration")]
// TODO: That this can occur at all is a bug.
// See https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/901#note_2858455
UnconfiguredTransportDueToConcurrentReconfiguration,
/// The pluggable transport reactor failed.
#[error("Internal error")]
Internal(#[from] tor_error::Bug),
}
impl HasKind for PtError {
fn kind(&self) -> ErrorKind {
use ErrorKind as EK;
use PtError as E;
match self {
E::ClientTransportsUnsupported(_) => EK::InvalidConfig,
E::ChildProtocolViolation(_)
| E::ProtocolViolation(_)
| E::UnsupportedVersion
| E::IpcParseFailed { .. } => EK::LocalProtocolViolation,
E::Timeout
| E::TransportGaveError { .. }
| E::ChildGone
| E::ChildReadFailed(_)
| E::ChildSpawnFailed { .. }
| E::ProxyError(_) => EK::ExternalToolFailed,
E::StatedirCreateFailed { .. } => EK::PersistentStateAccessFailed,
E::UnconfiguredTransportDueToConcurrentReconfiguration => EK::TransientFailure,
E::PathExpansionFailed { .. } => EK::InvalidConfig,
E::NotAFile { .. } => EK::InvalidConfig,
E::Internal(e) => e.kind(),
E::Spawn { cause, .. } => cause.kind(),
}
}
}
impl HasRetryTime for PtError {
fn retry_time(&self) -> RetryTime {
use PtError as E;
use RetryTime as RT;
match self {
E::ClientTransportsUnsupported(_)
| E::ChildProtocolViolation(_)
| E::ProtocolViolation(_)
| E::IpcParseFailed { .. }
| E::NotAFile { .. }
| E::UnsupportedVersion
| E::Internal(_)
| E::Spawn { .. }
| E::PathExpansionFailed { .. } => RT::Never,
E::StatedirCreateFailed { .. }
| E::TransportGaveError { .. }
| E::Timeout
| E::UnconfiguredTransportDueToConcurrentReconfiguration
| E::ProxyError(_)
| E::ChildGone
| E::ChildReadFailed(_) => RT::AfterWaiting,
E::ChildSpawnFailed { error, .. } => {
if error.kind() == std::io::ErrorKind::NotFound {
RT::Never
} else {
RT::AfterWaiting
}
}
}
}
}
impl AbstractPtError for PtError {}
/// Standard-issue `Result` alias, with [`PtError`].
pub type Result<T> = std::result::Result<T, PtError>;