Skip to content

Commit

Permalink
Implemented std::error::Error for error types
Browse files Browse the repository at this point in the history
  • Loading branch information
teawithsand committed Jul 2, 2021
1 parent caed51d commit c5cee8a
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
68 changes: 66 additions & 2 deletions src/control/conn/conn.rs
@@ -1,9 +1,15 @@
use std::convert::TryFrom;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::num::ParseIntError;
use std::option::Option::None;
use std::str::{FromStr, Utf8Error};
use std::string::FromUtf8Error;
use tokio::io::{AsyncRead, AsyncWrite, AsyncReadExt, AsyncWriteExt};

use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};

use crate::control::TorErrorKind;

/// UnauthenticatedConnError describes subset of `ConnError`s returned by `UnauthenticatedConn`
#[derive(Debug, From)]
Expand All @@ -19,6 +25,16 @@ pub enum UnauthenticatedConnError {
ServerHashMismatch,
}

impl Display for UnauthenticatedConnError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InfoFetchedTwice => write!(f, "Authentication info fetched twice"),
Self::ServerHashMismatch => write!(f, "Tor cookie hashes do not match"),
}
}
}

impl Error for UnauthenticatedConnError {}

/// AuthenticatedConnError describes subset of `ConnError`s returned by `AuthenticatedConn`
#[derive(Debug, From)]
Expand All @@ -41,6 +57,16 @@ pub enum AuthenticatedConnError {
InvalidEventName,
}

impl Display for AuthenticatedConnError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
// TODO(teawithsand): proper explanation for these errors
// despite the fact that they are low level it's hard to write user facing message for them
write!(f, "{:?} (Read torut's docs)", self)
}
}

impl Error for AuthenticatedConnError {}

/// ConnError is able to wrap any error that a connection may return
#[derive(Debug, From)]
pub enum ConnError {
Expand All @@ -53,6 +79,7 @@ pub enum ConnError {
AuthenticatedConnError(AuthenticatedConnError),

// TODO(teawithsand): migrate this error to more meaningful one - with explanation or unknown code otherwise
// typed error codes are already implemented; change this before next minor release
/// Invalid(or unexpected) response code was returned from tor controller.
/// Usually this indicates some error on tor's side
InvalidResponseCode(u16),
Expand All @@ -65,6 +92,43 @@ pub enum ConnError {
TooManyBytesRead,
}

impl Display for ConnError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let src = self.source();
if let Some(src) = src {
write!(f, "ConnError: {}", src)
} else {
match self {
Self::InvalidResponseCode(code) => {
let typed = TorErrorKind::try_from(*code);
if let Ok(typed) = typed {
write!(f, "Tor returned error response code: {} - {:?}", code, typed)
} else {
write!(f, "Tor returned error response code: {}", code)
}
}
Self::InvalidFormat | Self::InvalidCharacterFound | Self::NonAsciiByteFound | Self::ResponseCodeMismatch => write!(f, "Invalid response got from tor"),
Self::TooManyBytesRead => write!(f, "Tor response was too big to process"),
_ => write!(f, "Unknown ConnError"),
}
}
}
}

impl Error for ConnError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::IOError(err) => Some(err),
Self::Utf8Error(err) => Some(err),
Self::FromUtf8Error(err) => Some(err),
Self::ParseIntError(err) => Some(err),
Self::UnauthenticatedConnError(err) => Some(err),
Self::AuthenticatedConnError(err) => Some(err),
_ => None
}
}
}

/// Conn wraps any `AsyncRead + AsyncWrite` stream and implements parsing responses from tor and sending data to it.
///
/// It's stateless component. It does not contain any information about connection like authentication state.
Expand All @@ -73,7 +137,7 @@ pub enum ConnError {
/// This is fairly low-level connection which does only basic parsing.
/// Unless you need it you should use higher level apis.
pub struct Conn<S> {
stream: S
stream: S,
}

impl<S> Conn<S> {
Expand Down
15 changes: 10 additions & 5 deletions src/onion/v2/onion.rs
@@ -1,11 +1,15 @@
//! onion module contains utils for working with Tor's onion services

use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::str::FromStr;

#[cfg(feature = "serialize")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

use crate::utils::BASE32_ALPHA;

// use crate::onion::TorPublicKeyV2;

pub const TORV2_ONION_ADDRESS_LENGTH_BYTES: usize = 10;
Expand All @@ -21,13 +25,12 @@ pub const TORV2_ONION_ADDRESS_LENGTH_BYTES: usize = 10;
/// # Note
/// Onion address V2 does not contain checksum so any combination of random ten bytes satisfies requirements.
/// Since it may be valid SHA1 bytes.
///
///
/// # Docs
/// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v2.txt#n530
#[derive(Clone, Copy)]
pub struct OnionAddressV2([u8; TORV2_ONION_ADDRESS_LENGTH_BYTES]);

// TODO(teaiwthsand): implement it
// looks like Shallot does this
// https://github.com/katmagic/Shallot/blob/master/src/thread.c
/*
Expand Down Expand Up @@ -96,12 +99,14 @@ pub enum OnionAddressV2ParseError {
InvalidVersion,
}

impl std::fmt::Display for OnionAddressV2ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "OnionAddressParseError occurred")
impl Display for OnionAddressV2ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Filed to parse OnionAddressV2")
}
}

impl Error for OnionAddressV2ParseError {}


impl FromStr for OnionAddressV2 {
type Err = OnionAddressV2ParseError;
Expand Down
14 changes: 11 additions & 3 deletions src/onion/v3/onion.rs
@@ -1,5 +1,8 @@
//! onion module contains utils for working with Tor's onion services

use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::str::FromStr;

#[cfg(feature = "serialize")]
Expand Down Expand Up @@ -91,6 +94,9 @@ impl OnionAddressV3 {
}
}

// soon it will be the only onion address to parse
// so let's leave name not fixed
// it should be OnionAddressV3ParseError
#[derive(Debug)]
pub enum OnionAddressParseError {
InvalidLength,
Expand All @@ -99,12 +105,14 @@ pub enum OnionAddressParseError {
InvalidVersion,
}

impl std::fmt::Display for OnionAddressParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "OnionAddressParseError occurred")
impl Display for OnionAddressParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Filed to parse OnionAddressV3")
}
}

impl Error for OnionAddressParseError {}

impl FromStr for OnionAddressV3 {
type Err = OnionAddressParseError;

Expand Down

0 comments on commit c5cee8a

Please sign in to comment.