Add a separate trait for converting errors into server responses.

This commit is contained in:
2021-11-21 21:08:29 -08:00
parent 774591cb54
commit 74f66ef747
4 changed files with 34 additions and 11 deletions

View File

@@ -1,4 +1,5 @@
use crate::errors::{DeserializationError, SerializationError}; use crate::errors::{DeserializationError, SerializationError};
use crate::network::generic::IntoErrorResponse;
use crate::network::SOCKSv5Address; use crate::network::SOCKSv5Address;
use crate::serialize::read_amt; use crate::serialize::read_amt;
use crate::standard_roundtrip; use crate::standard_roundtrip;
@@ -37,6 +38,12 @@ pub enum ServerResponseStatus {
AddressTypeNotSupported, AddressTypeNotSupported,
} }
impl IntoErrorResponse for ServerResponseStatus {
fn into_response(&self) -> ServerResponseStatus {
self.clone()
}
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct ServerResponse { pub struct ServerResponse {
pub status: ServerResponseStatus, pub status: ServerResponseStatus,
@@ -45,9 +52,9 @@ pub struct ServerResponse {
} }
impl ServerResponse { impl ServerResponse {
pub fn error<E: Into<ServerResponseStatus>>(resp: E) -> ServerResponse { pub fn error<E: IntoErrorResponse>(resp: &E) -> ServerResponse {
ServerResponse { ServerResponse {
status: resp.into(), status: resp.into_response(),
bound_address: SOCKSv5Address::IP4(Ipv4Addr::new(0, 0, 0, 0)), bound_address: SOCKSv5Address::IP4(Ipv4Addr::new(0, 0, 0, 0)),
bound_port: 0, bound_port: 0,
} }
@@ -189,7 +196,7 @@ fn check_bad_command() {
#[test] #[test]
fn short_write_fails_right() { fn short_write_fails_right() {
let mut buffer = [0u8; 2]; let mut buffer = [0u8; 2];
let cmd = ServerResponse::error(ServerResponseStatus::AddressTypeNotSupported); let cmd = ServerResponse::error(&ServerResponseStatus::AddressTypeNotSupported);
let mut cursor = Cursor::new(&mut buffer as &mut [u8]); let mut cursor = Cursor::new(&mut buffer as &mut [u8]);
let result = task::block_on(cmd.write(&mut cursor)); let result = task::block_on(cmd.write(&mut cursor));
match result { match result {

View File

@@ -4,7 +4,7 @@ use crate::network::datagram::GenericDatagramSocket;
use crate::network::listener::GenericListener; use crate::network::listener::GenericListener;
use crate::network::stream::GenericStream; use crate::network::stream::GenericStream;
use async_trait::async_trait; use async_trait::async_trait;
use std::fmt::Display; use std::fmt::{Debug, Display};
#[async_trait] #[async_trait]
pub trait Networklike { pub trait Networklike {
@@ -12,7 +12,7 @@ pub trait Networklike {
/// for using only one; if you have a use case for separating your errors, /// for using only one; if you have a use case for separating your errors,
/// please shoot the author(s) and email to split this into multiple types, one /// please shoot the author(s) and email to split this into multiple types, one
/// for each trait function. /// for each trait function.
type Error: Display + Into<ServerResponseStatus> + Send; type Error: Debug + Display + IntoErrorResponse + Send;
/// Connect to the given address and port, over this kind of network. The /// Connect to the given address and port, over this kind of network. The
/// underlying stream should behave somewhat like a TCP stream ... which /// underlying stream should behave somewhat like a TCP stream ... which
@@ -46,3 +46,16 @@ pub trait Networklike {
port: u16, port: u16,
) -> Result<GenericDatagramSocket<Self::Error>, Self::Error>; ) -> Result<GenericDatagramSocket<Self::Error>, Self::Error>;
} }
/// This trait is a hack; sorry about that. The thing is, we want to be able to
/// convert Errors from the `Networklike` trait into a `ServerResponseStatus`,
/// but want to do so on references to the error object rather than the actual
/// object. This is for the paired reason that (a) we want to be able to use
/// the errors in multiple places -- for example, to return a value to the client
/// and then also to whoever called the function -- and (b) some common errors
/// (I'm looking at you, `io::Error`) aren't `Clone`. So ... hence this overly-
/// specific trait.
pub trait IntoErrorResponse {
#[allow(clippy::wrong_self_convention)]
fn into_response(&self) -> ServerResponseStatus;
}

View File

@@ -13,6 +13,9 @@ use async_trait::async_trait;
use futures::AsyncWriteExt; use futures::AsyncWriteExt;
use log::error; use log::error;
use super::generic::IntoErrorResponse;
#[derive(Clone)]
pub struct Builtin {} pub struct Builtin {}
impl Builtin { impl Builtin {
@@ -226,9 +229,9 @@ fn check_sanity() {
}); });
} }
impl From<io::Error> for ServerResponseStatus { impl IntoErrorResponse for io::Error {
fn from(e: io::Error) -> ServerResponseStatus { fn into_response(&self) -> ServerResponseStatus {
match e.kind() { match self.kind() {
io::ErrorKind::ConnectionRefused => ServerResponseStatus::ConnectionRefused, io::ErrorKind::ConnectionRefused => ServerResponseStatus::ConnectionRefused,
io::ErrorKind::NotFound => ServerResponseStatus::HostUnreachable, io::ErrorKind::NotFound => ServerResponseStatus::HostUnreachable,
_ => ServerResponseStatus::GeneralFailure, _ => ServerResponseStatus::GeneralFailure,

View File

@@ -6,7 +6,7 @@ use crate::network::address::{HasLocalAddress, SOCKSv5Address};
#[cfg(test)] #[cfg(test)]
use crate::network::datagram::Datagramlike; use crate::network::datagram::Datagramlike;
use crate::network::datagram::GenericDatagramSocket; use crate::network::datagram::GenericDatagramSocket;
use crate::network::generic::Networklike; use crate::network::generic::{IntoErrorResponse, Networklike};
use crate::network::listener::{GenericListener, Listenerlike}; use crate::network::listener::{GenericListener, Listenerlike};
use crate::network::stream::GenericStream; use crate::network::stream::GenericStream;
use crate::network::testing::datagram::TestDatagram; use crate::network::testing::datagram::TestDatagram;
@@ -82,8 +82,8 @@ impl fmt::Display for TestStackError {
} }
} }
impl From<TestStackError> for ServerResponseStatus { impl IntoErrorResponse for TestStackError {
fn from(_: TestStackError) -> Self { fn into_response(&self) -> ServerResponseStatus {
ServerResponseStatus::GeneralFailure ServerResponseStatus::GeneralFailure
} }
} }