diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index b4a953597e..5956910093 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -2605,6 +2605,7 @@ impl Connection { code: TransportErrorCode::crypto(0x6d), frame: None, reason: "transport parameters missing".into(), + crypto: None, })?; if self.has_0rtt() { @@ -2678,6 +2679,7 @@ impl Connection { code: TransportErrorCode::crypto(0x6d), frame: None, reason: "transport parameters missing".into(), + crypto: None, })?; self.handle_peer_params(params)?; self.issue_first_cids(now); diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index c31fddf870..48891fd88f 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -110,6 +110,7 @@ impl crypto::Session for TlsSession { code: TransportErrorCode::crypto(alert.into()), frame: None, reason: e.to_string(), + crypto: Some(Arc::new(e)), } } else { TransportError::PROTOCOL_VIOLATION(format!("TLS error: {e}")) diff --git a/quinn-proto/src/transport_error.rs b/quinn-proto/src/transport_error.rs index 047cd0acc1..21e6adca82 100644 --- a/quinn-proto/src/transport_error.rs +++ b/quinn-proto/src/transport_error.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, sync::Arc}; use bytes::{Buf, BufMut}; @@ -8,7 +8,8 @@ use crate::{ }; /// Transport-level errors occur when a peer violates the protocol specification -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] +#[non_exhaustive] pub struct Error { /// Type of error pub code: Code, @@ -16,8 +17,18 @@ pub struct Error { pub frame: Option, /// Human-readable explanation of the reason pub reason: String, + /// An underlying crypto (e.g. TLS) layer error + pub crypto: Option>, } +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + self.code == other.code + } +} + +impl Eq for Error {} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.code.fmt(f)?; @@ -39,6 +50,19 @@ impl From for Error { code: x, frame: None, reason: "".to_string(), + crypto: None, + } + } +} + +impl Error { + /// Construct an error with a code and a reason + pub fn new(code: Code, reason: String) -> Self { + Self { + code, + frame: None, + reason, + crypto: None, } } } @@ -79,6 +103,7 @@ macro_rules! errors { code: Code::$name, frame: None, reason: reason.into(), + crypto: None, } } )* diff --git a/quinn/src/connection.rs b/quinn/src/connection.rs index ab3777d713..5b99401752 100644 --- a/quinn/src/connection.rs +++ b/quinn/src/connection.rs @@ -1074,11 +1074,10 @@ impl State { self.close(error_code, reason, shared); } Poll::Ready(None) => { - return Err(ConnectionError::TransportError(proto::TransportError { - code: proto::TransportErrorCode::INTERNAL_ERROR, - frame: None, - reason: "endpoint driver future was dropped".to_string(), - })); + return Err(ConnectionError::TransportError(proto::TransportError::new( + proto::TransportErrorCode::INTERNAL_ERROR, + "endpoint driver future was dropped".to_string(), + ))); } Poll::Pending => { return Ok(());