1use fs_mistrust::anon_home::PathExt as _;
4use futures::task::SpawnError;
5use std::path::PathBuf;
6use std::sync::Arc;
7use tor_chanmgr::factory::AbstractPtError;
8use tor_config_path::{CfgPath, CfgPathError};
9use tor_error::{ErrorKind, HasKind, HasRetryTime, RetryTime};
10
11#[derive(Clone, Debug, thiserror::Error)]
13#[non_exhaustive]
14pub enum PtError {
15 #[error("PT launch timed out")]
17 Timeout,
18 #[error("PT binary does not support transports: {0:?}")]
20 ClientTransportsUnsupported(Vec<String>),
21 #[error("Transport '{}' failed to launch, saying: {:?}", transport, message)]
24 TransportGaveError {
25 transport: String,
27 message: String,
29 },
30 #[error("PT reported protocol error: {0}")]
32 ChildProtocolViolation(String),
33 #[error("PT violated protocol: {0}")]
35 ProtocolViolation(String),
36 #[error("PT binary uses unsupported protocol version")]
38 UnsupportedVersion,
39 #[error("PT binary failed to use proxy URI: {0}")]
41 ProxyError(String),
42 #[error("PT binary gone")]
44 ChildGone,
45 #[error("Failed to read from PT binary: {0}")]
48 ChildReadFailed(Arc<std::io::Error>),
49 #[error("Couldn't execute PT binary at {}: {}", path.anonymize_home(), error)]
51 ChildSpawnFailed {
52 path: PathBuf,
54 #[source]
56 error: Arc<std::io::Error>,
57 },
58 #[error("Couldn't parse IPC line \"{}\": {}", line, error)]
60 IpcParseFailed {
61 line: String,
63 error: String,
65 },
66 #[error("Failed to create a state directory at {}: {}", path.anonymize_home(), error)]
68 StatedirCreateFailed {
69 path: PathBuf,
71 #[source]
73 error: Arc<std::io::Error>,
74 },
75 #[error("Failed to expand path {}: {}", path, error)]
77 PathExpansionFailed {
78 path: CfgPath,
80 #[source]
82 error: CfgPathError,
83 },
84 #[error("Configured binary path {} doesn't have syntax of a file", path.anonymize_home())]
90 NotAFile {
91 path: PathBuf,
93 },
94 #[error("Unable to spawn reactor task.")]
96 Spawn {
97 #[source]
99 cause: Arc<SpawnError>,
100 },
101 #[error("Transport not found due to concurrent reconfiguration")]
103 UnconfiguredTransportDueToConcurrentReconfiguration,
106 #[error("Internal error")]
108 Internal(#[from] tor_error::Bug),
109}
110
111impl HasKind for PtError {
112 fn kind(&self) -> ErrorKind {
113 use ErrorKind as EK;
114 use PtError as E;
115 match self {
116 E::ClientTransportsUnsupported(_) => EK::InvalidConfig,
117 E::ChildProtocolViolation(_)
118 | E::ProtocolViolation(_)
119 | E::UnsupportedVersion
120 | E::IpcParseFailed { .. } => EK::LocalProtocolViolation,
121 E::Timeout
122 | E::TransportGaveError { .. }
123 | E::ChildGone
124 | E::ChildReadFailed(_)
125 | E::ChildSpawnFailed { .. }
126 | E::ProxyError(_) => EK::ExternalToolFailed,
127 E::StatedirCreateFailed { .. } => EK::PersistentStateAccessFailed,
128 E::UnconfiguredTransportDueToConcurrentReconfiguration => EK::TransientFailure,
129 E::PathExpansionFailed { .. } => EK::InvalidConfig,
130 E::NotAFile { .. } => EK::InvalidConfig,
131 E::Internal(e) => e.kind(),
132 E::Spawn { cause, .. } => cause.kind(),
133 }
134 }
135}
136
137impl HasRetryTime for PtError {
138 fn retry_time(&self) -> RetryTime {
139 use PtError as E;
140 use RetryTime as RT;
141 match self {
142 E::ClientTransportsUnsupported(_)
143 | E::ChildProtocolViolation(_)
144 | E::ProtocolViolation(_)
145 | E::IpcParseFailed { .. }
146 | E::NotAFile { .. }
147 | E::UnsupportedVersion
148 | E::Internal(_)
149 | E::Spawn { .. }
150 | E::PathExpansionFailed { .. } => RT::Never,
151 E::StatedirCreateFailed { .. }
152 | E::TransportGaveError { .. }
153 | E::Timeout
154 | E::UnconfiguredTransportDueToConcurrentReconfiguration
155 | E::ProxyError(_)
156 | E::ChildGone
157 | E::ChildReadFailed(_) => RT::AfterWaiting,
158 E::ChildSpawnFailed { error, .. } => {
159 if error.kind() == std::io::ErrorKind::NotFound {
160 RT::Never
161 } else {
162 RT::AfterWaiting
163 }
164 }
165 }
166 }
167}
168
169impl AbstractPtError for PtError {}
170
171pub type Result<T> = std::result::Result<T, PtError>;