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
|
//! Declare an error type for the `tor-hsservice` crate.
use std::sync::Arc;
use futures::task::SpawnError;
use thiserror::Error;
use tor_error::{Bug, ErrorKind, HasKind};
use tor_keymgr::KeystoreError;
pub use crate::svc::rend_handshake::{EstablishSessionError, IntroRequestError};
/// An error which occurs trying to create and start up an onion service
///
/// This is only returned by startup methods.
/// After the service is created and started,
/// we will continue to try keep the service alive,
/// retrying things as necessary.
#[derive(Clone, Debug, Error)]
#[non_exhaustive]
pub enum StartupError {
/// A keystore operation failed.
#[error("Keystore error while attempting to {action}")]
Keystore {
/// The action we were trying to perform.
action: &'static str,
/// The underlying error
#[source]
cause: Box<dyn KeystoreError>,
},
/// Keystore corruption.
#[error("The keystore is unrecoverably corrupt")]
KeystoreCorrupted,
/// Unable to spawn task
//
// TODO too many types have an open-coded version of FooError::Spawn
// Instead we should:
// * Have tor_rtcompat provide a SpawnError struct which contains the task identifier
// * Have tor_rtcompat provide a spawn method that takes an identifier
// (and which passes that identifier to runtimes that support such a thing,
// including our own mock spawner)
// * Change every crate's task spawning and error handling to use the new things
// (breaking changes to the error type, unless we retain unused compat error variants)
#[error("Unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
/// Tried to launch an onion service that has already been launched.
#[error("Onion service has already been launched")]
AlreadyLaunched,
}
impl HasKind for StartupError {
fn kind(&self) -> ErrorKind {
use ErrorKind as EK;
use StartupError as E;
match self {
E::Keystore { cause, .. } => cause.kind(),
E::KeystoreCorrupted => EK::KeystoreCorrupted,
E::Spawn { cause, .. } => cause.kind(),
E::AlreadyLaunched => EK::BadApiUsage,
}
}
}
/// An error which occurs trying to communicate with a particular client.
///
/// This is returned by `RendRequest::accept` and `StreamRequest::accept`.
#[derive(Clone, Debug, Error)]
#[non_exhaustive]
pub enum ClientError {
/// Failed to process an INTRODUCE2 request.
#[error("Could not process INTRODUCE request")]
BadIntroduce(#[source] IntroRequestError),
/// Failed to complete a rendezvous request.
#[error("Could not connect rendezvous circuit.")]
EstablishSession(#[source] EstablishSessionError),
/// Failed to send a CONNECTED message and get a stream.
#[error("Could not accept stream from rendezvous circuit")]
AcceptStream(#[source] tor_proto::Error),
/// Failed to send a END message and reject a stream.
#[error("Could not reject stream from rendezvous circuit")]
RejectStream(#[source] tor_proto::Error),
}
impl HasKind for ClientError {
fn kind(&self) -> ErrorKind {
match self {
ClientError::BadIntroduce(e) => e.kind(),
ClientError::EstablishSession(e) => e.kind(),
ClientError::AcceptStream(e) => e.kind(),
ClientError::RejectStream(e) => e.kind(),
}
}
}
/// An error which means we cannot continue to try to operate an onion service.
///
/// These errors only occur during operation, and only for catastrophic reasons
/// (such as the async reactor shutting down).
//
// TODO HSS where is FatalError emitted from this crate into the wider program ?
// Perhaps there will be some kind of monitoring handle that can produce one of these.
#[derive(Clone, Debug, Error)]
#[non_exhaustive]
pub enum FatalError {
/// Unable to spawn task
#[error("Unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
/// Failed to access the keystore.
#[error("failed to access keystore")]
Keystore(#[from] Box<dyn KeystoreError>),
/// A key we needed could not be found in the keystore.
//
// TODO HSS: considering adding (Box<dyn KeySpecifier>, KeyType) to the error context and
// making the inner type a KeyNotFoundError.
//
// See https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1677#note_2955706
#[error("A key we needed could not be found in the keystore: {0}")]
MissingKey(String),
/// An error caused by a programming issue . or a failure in another
/// library that we can't work around.
#[error("Programming error")]
Bug(#[from] Bug),
}
|