Lines
24.07 %
Functions
13.79 %
Branches
100 %
//! Define an error type for the tor-proto crate.
use std::sync::Arc;
use thiserror::Error;
use tor_cell::relaycell::msg::EndReason;
use tor_error::{ErrorKind, HasKind};
/// An error type for the tor-proto crate.
///
/// This type should probably be split into several. There's more
/// than one kind of error that can occur while doing something with
/// the Tor protocol.
#[derive(Error, Debug, Clone)]
#[non_exhaustive]
pub enum Error {
/// An error that occurred in the tor_bytes crate while decoding an
/// object.
#[error("parsing error: {0}")]
BytesErr(#[from] tor_bytes::Error),
/// An error that occurred from the io system when using a
/// channel.
#[error("io error on channel: {0}")]
ChanIoErr(#[source] Arc<std::io::Error>),
/// An error from the io system that occurred when trying to connect a channel.
#[error("io error in handshake: {0}")]
HandshakeIoErr(#[source] Arc<std::io::Error>),
/// An error occurred in the cell-handling layer.
#[error("cell encoding error: {0}")]
CellErr(#[source] tor_cell::Error),
/// We tried to produce too much output for some function.
#[error("couldn't produce that much output")]
InvalidOutputLength,
/// We tried to encrypt a message to a hop that wasn't there.
#[error("tried to encrypt to nonexistent hop")]
NoSuchHop,
/// The authentication information on this cell was completely wrong,
/// or the cell was corrupted.
#[error("bad relay cell authentication")]
BadCellAuth,
/// A circuit-extension handshake failed.
#[error("handshake failed")]
BadCircHandshake,
/// Handshake protocol violation.
#[error("handshake protocol violation: {0}")]
HandshakeProto(String),
/// Protocol violation at the channel level, other than at the handshake
/// stage.
#[error("channel protocol violation: {0}")]
ChanProto(String),
/// Protocol violation at the circuit level
#[error("circuit protocol violation: {0}")]
CircProto(String),
/// Channel is closed.
#[error("channel closed")]
ChannelClosed,
/// Circuit is closed.
#[error("circuit closed")]
CircuitClosed,
/// Can't allocate any more circuit or stream IDs on a channel.
#[error("too many entries in map: can't allocate ID")]
IdRangeFull,
/// Couldn't extend a circuit because the extending relay or the
/// target relay refused our request.
#[error("circuit extension handshake error: {0}")]
CircRefused(&'static str),
/// Tried to make or use a stream to an invalid destination address.
#[error("invalid stream target address")]
BadStreamAddress,
/// Received an End cell from the other end of a stream.
#[error("Received an End cell with reason {0}")]
EndReceived(EndReason),
/// Stream was already closed when we tried to use it.
#[error("stream not connected")]
NotConnected,
/// Stream protocol violation
#[error("stream protocol violation: {0}")]
StreamProto(String),
/// Channel does not match target
#[error("channel mismatch: {0}")]
ChanMismatch(String),
/// There was a programming error somewhere in our code, or the calling code.
#[error("Programming error: {0}")]
Bug(#[from] tor_error::Bug),
/// Remote DNS lookup failed.
#[error("remote resolve failed: {0}")]
ResolveError(String),
}
impl From<tor_cell::Error> for Error {
fn from(err: tor_cell::Error) -> Error {
match err {
tor_cell::Error::ChanProto(msg) => Error::ChanProto(msg),
_ => Error::CellErr(err),
impl From<Error> for std::io::Error {
fn from(err: Error) -> std::io::Error {
use std::io::ErrorKind;
use Error::*;
let kind = match err {
ChanIoErr(e) | HandshakeIoErr(e) => match Arc::try_unwrap(e) {
Ok(e) => return e,
Err(arc) => return std::io::Error::new(arc.kind(), arc),
},
InvalidOutputLength | NoSuchHop | BadStreamAddress => ErrorKind::InvalidInput,
NotConnected => ErrorKind::NotConnected,
EndReceived(end_reason) => end_reason.into(),
ChannelClosed | CircuitClosed => ErrorKind::ConnectionReset,
BytesErr(_) | BadCellAuth | BadCircHandshake | HandshakeProto(_) | ChanProto(_)
| CircProto(_) | CellErr(_) | ChanMismatch(_) | StreamProto(_) => {
ErrorKind::InvalidData
Bug(ref e) if e.kind() == tor_error::ErrorKind::BadApiUsage => ErrorKind::InvalidData,
IdRangeFull | CircRefused(_) | ResolveError(_) | Bug(_) => ErrorKind::Other,
};
std::io::Error::new(kind, err)
impl HasKind for Error {
fn kind(&self) -> ErrorKind {
use tor_bytes::Error as BytesError;
use Error as E;
use ErrorKind as EK;
match self {
E::BytesErr(BytesError::Bug(e)) => e.kind(),
E::BytesErr(_) => EK::TorProtocolViolation,
E::ChanIoErr(_) => EK::LocalNetworkError,
E::HandshakeIoErr(_) => EK::TorAccessFailed,
E::CellErr(e) => e.kind(),
E::InvalidOutputLength => EK::Internal,
E::NoSuchHop => EK::BadApiUsage,
E::BadCellAuth => EK::TorProtocolViolation,
E::BadCircHandshake => EK::TorProtocolViolation,
E::HandshakeProto(_) => EK::TorAccessFailed,
E::ChanProto(_) => EK::TorProtocolViolation,
E::CircProto(_) => EK::TorProtocolViolation,
E::ChannelClosed | E::CircuitClosed => EK::CircuitCollapse,
E::IdRangeFull => EK::BadApiUsage,
E::CircRefused(_) => EK::CircuitRefused,
E::BadStreamAddress => EK::BadApiUsage,
E::EndReceived(reason) => reason.kind(),
E::NotConnected => EK::BadApiUsage,
E::StreamProto(_) => EK::TorProtocolViolation,
E::ChanMismatch(_) => EK::RelayIdMismatch,
E::ResolveError(_) => EK::RemoteHostNotFound,
E::Bug(e) => e.kind(),
/// Internal type: Error return value from reactor's run_once
/// function: indicates an error or a shutdown.
#[derive(Debug)]
pub(crate) enum ReactorError {
/// The reactor should shut down with an abnormal exit condition.
Err(Error),
/// The reactor should shut down without an error, since all is well.
Shutdown,
impl From<Error> for ReactorError {
fn from(e: Error) -> ReactorError {
ReactorError::Err(e)
#[cfg(test)]
impl ReactorError {
/// Tests only: assert that this is an Error, and return it.
pub(crate) fn unwrap_err(self) -> Error {
ReactorError::Shutdown => panic!(),
ReactorError::Err(e) => e,