mirror of
https://github.com/MercuryWorkshop/epoxy-tls.git
synced 2025-05-12 14:00:01 -04:00
use thiserror and add new close reason
This commit is contained in:
parent
065de8e85f
commit
65a7904437
4 changed files with 78 additions and 96 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -2210,18 +2210,18 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.64"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.64"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3015,6 +3015,7 @@ dependencies = [
|
|||
"getrandom",
|
||||
"nohash-hasher",
|
||||
"pin-project-lite",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ futures-timer = "3.0.3"
|
|||
getrandom = { version = "0.2.15", features = ["std"], optional = true }
|
||||
nohash-hasher = "0.2.0"
|
||||
pin-project-lite = "0.2.14"
|
||||
thiserror = "1.0.65"
|
||||
tokio = { version = "1.39.3", optional = true, default-features = false }
|
||||
|
||||
[features]
|
||||
|
|
106
wisp/src/lib.rs
106
wisp/src/lib.rs
|
@ -33,6 +33,7 @@ use std::{
|
|||
},
|
||||
time::Duration,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use ws::{AppendingWebSocketRead, LockedWebSocketWrite, Payload};
|
||||
|
||||
/// Wisp version supported by this crate.
|
||||
|
@ -48,133 +49,86 @@ pub enum Role {
|
|||
}
|
||||
|
||||
/// Errors the Wisp implementation can return.
|
||||
#[derive(Debug)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum WispError {
|
||||
/// The packet received did not have enough data.
|
||||
#[error("Packet too small")]
|
||||
PacketTooSmall,
|
||||
/// The packet received had an invalid type.
|
||||
#[error("Invalid packet type")]
|
||||
InvalidPacketType,
|
||||
/// The stream had an invalid ID.
|
||||
#[error("Invalid steam ID")]
|
||||
InvalidStreamId,
|
||||
/// The close packet had an invalid reason.
|
||||
#[error("Invalid close reason")]
|
||||
InvalidCloseReason,
|
||||
/// The URI received was invalid.
|
||||
InvalidUri,
|
||||
/// The URI received had no host.
|
||||
UriHasNoHost,
|
||||
/// The URI received had no port.
|
||||
UriHasNoPort,
|
||||
/// The max stream count was reached.
|
||||
#[error("Maximum stream count reached")]
|
||||
MaxStreamCountReached,
|
||||
/// The Wisp protocol version was incompatible.
|
||||
IncompatibleProtocolVersion,
|
||||
#[error("Incompatible Wisp protocol version: found {0} but needed {1}")]
|
||||
IncompatibleProtocolVersion(WispVersion, WispVersion),
|
||||
/// The stream had already been closed.
|
||||
#[error("Stream already closed")]
|
||||
StreamAlreadyClosed,
|
||||
|
||||
/// The websocket frame received had an invalid type.
|
||||
#[error("Invalid websocket frame type: {0:?}")]
|
||||
WsFrameInvalidType(ws::OpCode),
|
||||
/// The websocket frame received was not finished.
|
||||
#[error("Unfinished websocket frame")]
|
||||
WsFrameNotFinished,
|
||||
/// Error specific to the websocket implementation.
|
||||
#[error("Websocket implementation error:")]
|
||||
WsImplError(Box<dyn std::error::Error + Sync + Send>),
|
||||
/// The websocket implementation socket closed.
|
||||
#[error("Websocket implementation error: socket closed")]
|
||||
WsImplSocketClosed,
|
||||
/// The websocket implementation did not support the action.
|
||||
#[error("Websocket implementation error: not supported")]
|
||||
WsImplNotSupported,
|
||||
|
||||
/// The string was invalid UTF-8.
|
||||
Utf8Error(std::str::Utf8Error),
|
||||
#[error("UTF-8 error: {0}")]
|
||||
Utf8Error(#[from] std::str::Utf8Error),
|
||||
/// The integer failed to convert.
|
||||
TryFromIntError(std::num::TryFromIntError),
|
||||
#[error("Integer conversion error: {0}")]
|
||||
TryFromIntError(#[from] std::num::TryFromIntError),
|
||||
/// Other error.
|
||||
#[error("Other: {0:?}")]
|
||||
Other(Box<dyn std::error::Error + Sync + Send>),
|
||||
|
||||
/// Failed to send message to multiplexor task.
|
||||
#[error("Failed to send multiplexor message")]
|
||||
MuxMessageFailedToSend,
|
||||
/// Failed to receive message from multiplexor task.
|
||||
#[error("Failed to receive multiplexor message")]
|
||||
MuxMessageFailedToRecv,
|
||||
/// Multiplexor task ended.
|
||||
#[error("Multiplexor task ended")]
|
||||
MuxTaskEnded,
|
||||
/// Multiplexor task already started.
|
||||
#[error("Multiplexor task already started")]
|
||||
MuxTaskStarted,
|
||||
|
||||
/// Error specific to the protocol extension implementation.
|
||||
#[error("Protocol extension implementation error: {0:?}")]
|
||||
ExtensionImplError(Box<dyn std::error::Error + Sync + Send>),
|
||||
/// The protocol extension implementation did not support the action.
|
||||
#[error("Protocol extension implementation error: unsupported feature")]
|
||||
ExtensionImplNotSupported,
|
||||
/// The specified protocol extensions are not supported by the server.
|
||||
/// The specified protocol extensions are not supported by the other side.
|
||||
#[error("Protocol extensions {0:?} not supported")]
|
||||
ExtensionsNotSupported(Vec<u8>),
|
||||
/// The password authentication username/password was invalid.
|
||||
#[error("Password protocol extension: Invalid username/password")]
|
||||
PasswordExtensionCredsInvalid,
|
||||
/// The certificate authentication signature was invalid.
|
||||
#[error("Certificate authentication protocol extension: Invalid signature")]
|
||||
CertAuthExtensionSigInvalid,
|
||||
}
|
||||
|
||||
impl From<std::str::Utf8Error> for WispError {
|
||||
fn from(err: std::str::Utf8Error) -> Self {
|
||||
Self::Utf8Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::num::TryFromIntError> for WispError {
|
||||
fn from(value: std::num::TryFromIntError) -> Self {
|
||||
Self::TryFromIntError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WispError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
Self::PacketTooSmall => write!(f, "Packet too small"),
|
||||
Self::InvalidPacketType => write!(f, "Invalid packet type"),
|
||||
Self::InvalidStreamId => write!(f, "Invalid stream id"),
|
||||
Self::InvalidCloseReason => write!(f, "Invalid close reason"),
|
||||
Self::InvalidUri => write!(f, "Invalid URI"),
|
||||
Self::UriHasNoHost => write!(f, "URI has no host"),
|
||||
Self::UriHasNoPort => write!(f, "URI has no port"),
|
||||
Self::MaxStreamCountReached => write!(f, "Maximum stream count reached"),
|
||||
Self::IncompatibleProtocolVersion => write!(f, "Incompatible Wisp protocol version"),
|
||||
Self::StreamAlreadyClosed => write!(f, "Stream already closed"),
|
||||
Self::WsFrameInvalidType(ty) => write!(f, "Invalid websocket frame type: {:?}", ty),
|
||||
Self::WsFrameNotFinished => write!(f, "Unfinished websocket frame"),
|
||||
Self::WsImplError(err) => write!(f, "Websocket implementation error: {}", err),
|
||||
Self::WsImplSocketClosed => {
|
||||
write!(f, "Websocket implementation error: websocket closed")
|
||||
}
|
||||
Self::WsImplNotSupported => {
|
||||
write!(f, "Websocket implementation error: unsupported feature")
|
||||
}
|
||||
Self::ExtensionImplError(err) => {
|
||||
write!(f, "Protocol extension implementation error: {}", err)
|
||||
}
|
||||
Self::ExtensionImplNotSupported => {
|
||||
write!(
|
||||
f,
|
||||
"Protocol extension implementation error: unsupported feature"
|
||||
)
|
||||
}
|
||||
Self::ExtensionsNotSupported(list) => {
|
||||
write!(f, "Protocol extensions {:?} not supported", list)
|
||||
}
|
||||
Self::Utf8Error(err) => write!(f, "UTF-8 error: {}", err),
|
||||
Self::TryFromIntError(err) => write!(f, "Integer conversion error: {}", err),
|
||||
Self::Other(err) => write!(f, "Other error: {}", err),
|
||||
Self::MuxMessageFailedToSend => write!(f, "Failed to send multiplexor message"),
|
||||
Self::MuxMessageFailedToRecv => write!(f, "Failed to receive multiplexor message"),
|
||||
Self::MuxTaskEnded => write!(f, "Multiplexor task ended"),
|
||||
Self::MuxTaskStarted => write!(f, "Multiplexor task already started"),
|
||||
Self::PasswordExtensionCredsInvalid => {
|
||||
write!(f, "Password extension: Invalid username/password")
|
||||
}
|
||||
Self::CertAuthExtensionSigInvalid => {
|
||||
write!(f, "Certificate authentication extension: Invalid signature")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for WispError {}
|
||||
|
||||
async fn maybe_wisp_v2<R>(
|
||||
read: &mut R,
|
||||
write: &LockedWebSocketWrite,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use crate::{
|
||||
extensions::{AnyProtocolExtension, AnyProtocolExtensionBuilder},
|
||||
ws::{self, Frame, LockedWebSocketWrite, OpCode, Payload, WebSocketRead},
|
||||
|
@ -59,8 +61,9 @@ mod close {
|
|||
Voluntary = 0x02,
|
||||
/// Unexpected stream closure due to a network error.
|
||||
Unexpected = 0x03,
|
||||
/// Incompatible extensions. Only used during the handshake.
|
||||
/// Incompatible extensions.
|
||||
ExtensionsIncompatible = 0x04,
|
||||
|
||||
/// Stream creation failed due to invalid information.
|
||||
ServerStreamInvalidInfo = 0x41,
|
||||
/// Stream creation failed due to an unreachable destination host.
|
||||
|
@ -75,31 +78,41 @@ mod close {
|
|||
ServerStreamBlockedAddress = 0x48,
|
||||
/// Connection throttled by the server.
|
||||
ServerStreamThrottled = 0x49,
|
||||
/// The client has encountered an unexpected error.
|
||||
|
||||
/// The client has encountered an unexpected error and is unable to recieve any more data.
|
||||
ClientUnexpected = 0x81,
|
||||
|
||||
/// Authentication failed due to invalid username/password.
|
||||
ExtensionsPasswordAuthFailed = 0xc0,
|
||||
/// Authentication failed due to invalid signature.
|
||||
ExtensionsCertAuthFailed = 0xc1,
|
||||
/// Authentication required but the client did not provide credentials.
|
||||
ExtensionsAuthRequired = 0xc2,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for CloseReason {
|
||||
type Error = WispError;
|
||||
fn try_from(close_reason: u8) -> Result<Self, Self::Error> {
|
||||
use CloseReason as R;
|
||||
match close_reason {
|
||||
0x01 => Ok(R::Unknown),
|
||||
0x02 => Ok(R::Voluntary),
|
||||
0x03 => Ok(R::Unexpected),
|
||||
0x04 => Ok(R::ExtensionsIncompatible),
|
||||
0x41 => Ok(R::ServerStreamInvalidInfo),
|
||||
0x42 => Ok(R::ServerStreamUnreachable),
|
||||
0x43 => Ok(R::ServerStreamConnectionTimedOut),
|
||||
0x44 => Ok(R::ServerStreamConnectionRefused),
|
||||
0x47 => Ok(R::ServerStreamTimedOut),
|
||||
0x48 => Ok(R::ServerStreamBlockedAddress),
|
||||
0x49 => Ok(R::ServerStreamThrottled),
|
||||
0x81 => Ok(R::ClientUnexpected),
|
||||
0x01 => Ok(Self::Unknown),
|
||||
0x02 => Ok(Self::Voluntary),
|
||||
0x03 => Ok(Self::Unexpected),
|
||||
0x04 => Ok(Self::ExtensionsIncompatible),
|
||||
|
||||
0x41 => Ok(Self::ServerStreamInvalidInfo),
|
||||
0x42 => Ok(Self::ServerStreamUnreachable),
|
||||
0x43 => Ok(Self::ServerStreamConnectionTimedOut),
|
||||
0x44 => Ok(Self::ServerStreamConnectionRefused),
|
||||
0x47 => Ok(Self::ServerStreamTimedOut),
|
||||
0x48 => Ok(Self::ServerStreamBlockedAddress),
|
||||
0x49 => Ok(Self::ServerStreamThrottled),
|
||||
|
||||
0x81 => Ok(Self::ClientUnexpected),
|
||||
|
||||
0xc0 => Ok(Self::ExtensionsPasswordAuthFailed),
|
||||
0xc1 => Ok(Self::ExtensionsCertAuthFailed),
|
||||
0xc2 => Ok(Self::ExtensionsAuthRequired),
|
||||
|
||||
_ => Err(Self::Error::InvalidCloseReason),
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +129,7 @@ mod close {
|
|||
C::Voluntary => "Voluntarily closed",
|
||||
C::Unexpected => "Unexpectedly closed",
|
||||
C::ExtensionsIncompatible => "Incompatible protocol extensions",
|
||||
|
||||
C::ServerStreamInvalidInfo =>
|
||||
"Stream creation failed due to invalid information",
|
||||
C::ServerStreamUnreachable =>
|
||||
|
@ -127,9 +141,12 @@ mod close {
|
|||
C::ServerStreamTimedOut => "TCP timed out",
|
||||
C::ServerStreamBlockedAddress => "Destination address is blocked",
|
||||
C::ServerStreamThrottled => "Throttled",
|
||||
|
||||
C::ClientUnexpected => "Client encountered unexpected error",
|
||||
|
||||
C::ExtensionsPasswordAuthFailed => "Invalid username/password",
|
||||
C::ExtensionsCertAuthFailed => "Invalid signature",
|
||||
C::ExtensionsAuthRequired => "Authentication required",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -271,6 +288,12 @@ pub struct WispVersion {
|
|||
pub minor: u8,
|
||||
}
|
||||
|
||||
impl Display for WispVersion {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}.{}", self.major, self.minor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Packet used in the initial handshake.
|
||||
///
|
||||
/// See [the docs](https://github.com/MercuryWorkshop/wisp-protocol/blob/main/protocol.md#0x05---info)
|
||||
|
@ -450,7 +473,10 @@ impl<'a> Packet<'a> {
|
|||
};
|
||||
|
||||
if version.major != WISP_VERSION.major {
|
||||
return Err(WispError::IncompatibleProtocolVersion);
|
||||
return Err(WispError::IncompatibleProtocolVersion(
|
||||
version,
|
||||
WISP_VERSION,
|
||||
));
|
||||
}
|
||||
|
||||
let mut extensions = Vec::new();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue