Skip to main content

tor_dirserver/
err.rs

1//! Error module for `tor-dirserver`.
2
3use std::{net::SocketAddr, string::FromUtf8Error};
4
5use retry_error::RetryError;
6use thiserror::Error;
7
8/// An error while communicating with a directory authority.
9///
10/// This error should be returned by all functions that download or upload
11/// resources to authorities, in other words: every function that interacts or
12/// communicates with a directory authority.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub(crate) enum AuthorityCommunicationError {
16    /// A TCP connection to an authority failed.
17    ///
18    /// A failure of this implies that both, the V4 and V6 (if present), have
19    /// failed.
20    #[error("TCP connection failure: {endpoints:?}: {error}")]
21    TcpConnect {
22        /// The [`SocketAddr`] items we tried to connect to, most typically
23        /// the IPv4 and IPv6 address + port of the directory authority.
24        endpoints: Vec<SocketAddr>,
25
26        /// The actual I/O error that happened.
27        error: std::io::Error,
28    },
29
30    /// A failure related to [`tor_dirclient`].
31    ///
32    /// Most likely, this will be of type [`tor_dirclient::Error::RequestFailed`],
33    /// but in order to stay compatible with `non_exhaustive` we map the error.
34    ///
35    /// The value is in a [`Box`] to satisfy `clippy::large_enum_variant`.
36    /// It is already noted in a TODO within the respective crate.
37    #[error("dirclient error: {0}")]
38    Dirclient(#[from] Box<tor_dirclient::Error>),
39
40    /// An internal error.
41    #[error("internal error")]
42    Bug(#[from] tor_error::Bug),
43}
44
45/// An error while interacting with a database.
46///
47/// This error should be returned by all functions that interact with the
48/// database in one way or another.
49#[derive(Debug, Error)]
50#[non_exhaustive]
51pub(crate) enum DatabaseError {
52    /// A low-level SQLite error has occurred, which can have a bascially
53    /// infinite amount of reasons, all of them outlined in the actual SQLite
54    /// and [`rusqlite`] documentation.
55    #[error("low-level rusqlite error: {0}")]
56    LowLevel(#[from] rusqlite::Error),
57
58    /// This is an application level error meaning that the database can be
59    /// successfully accessed but its content implies it is of a schema version
60    /// we do not support.
61    ///
62    /// Keep in mind that an unrecognized schema is not equal to no schema.
63    /// In the latter case we actually initialize the database, whereas in the
64    /// previous one, we fail early in order to not corrupt an existing database.
65    /// Future versions of this crate should continue with this promise in order
66    /// to ensure forward compatability.
67    #[error("incompatible schema version: {version}")]
68    IncompatibleSchema {
69        /// The incompatible schema version found in the database.
70        version: String,
71    },
72
73    /// Interaction with our database pool, [`r2d2`], has failed.
74    ///
75    /// Unlike other database pools, this error is fairly straightforward and
76    /// may only be obtained in the cases in which we try to obtain a connection
77    /// handle from the pool.  Notably, it does not fail if, for example,
78    /// the low-level [`rusqlite`] has a failure.
79    #[error("pool error: {0}")]
80    Pool(#[from] r2d2::Error),
81
82    /// An internal error.
83    #[error("Internal error")]
84    Bug(#[from] tor_error::Bug),
85}
86
87/// An unrecoverable error during daemon operation.
88///
89/// This error is inteded for functions that generally run forever, unless they
90/// encounter an error that is not recoverable, in which case, they will return
91/// this error type.
92#[derive(Debug, Error)]
93#[non_exhaustive]
94pub(crate) enum FatalError {
95    /// The selection of a consensus from the database has failed.
96    ///
97    /// This most likely indicates that something with the underlying database
98    /// is wrong in a persistent fashion, i.e. retries will not work anymore.
99    #[error("consensus selection error: {0}")]
100    ConsensusSelection(DatabaseError),
101}
102/// An error related to the request of a network document.
103///
104/// It mostly serves as an amalgamation of [`AuthorityCommunicationError`] and
105/// [`FromUtf8Error`] because UTF-8 is the mandatory encoding for network
106/// documents that is not enforced in the downloader per se.
107///
108/// TODO: Maybe the downloader should perform the UTF-8 conversion?
109#[derive(Debug, Error)]
110pub(crate) enum NetdocRequestError {
111    /// Downloading the network document failed.
112    #[error("download failed: {0:?}")]
113    Download(RetryError<AuthorityCommunicationError>),
114
115    /// Converting the network document to UTF-8 failed.
116    #[error("UTF-8 conversion failed: {0}")]
117    Utf8(#[from] FromUtf8Error),
118}