Skip to content

Commit

Permalink
lib: Add TryFrom<u64> for WireErrorCode
Browse files Browse the repository at this point in the history
This is a fallible conversion, since a peer could send an error
code value that is unknown to quiche itself.
  • Loading branch information
LPardue committed May 29, 2024
1 parent 731510e commit 98963e6
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
56 changes: 55 additions & 1 deletion quiche/src/h3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@
use std::collections::HashSet;
use std::collections::VecDeque;

#[cfg(feature = "sfv")]
use std::convert::TryFrom;
use std::fmt;
use std::fmt::Write;
Expand Down Expand Up @@ -476,6 +475,48 @@ pub enum WireErrorCode {
VersionFallback = 0x110,
}

/// Errors for conversions related to [WireErrorCode].
#[derive(Debug, Eq, PartialEq)]
pub enum FromWireConversionError {
/// The value was larger than the maximum encodable length.
TooBig,
/// The value was unknown by quiche, possibly a private extension or grease.
Unknown,
}

impl TryFrom<u64> for WireErrorCode {
type Error = FromWireConversionError;

fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
if value >= 1 << 62 {
return Err(FromWireConversionError::TooBig);
}

let res = match value {
0x100 => WireErrorCode::NoError,
0x101 => WireErrorCode::GeneralProtocolError,
0x102 => WireErrorCode::InternalError,
0x103 => WireErrorCode::StreamCreationError,
0x104 => WireErrorCode::ClosedCriticalStream,
0x105 => WireErrorCode::FrameUnexpected,
0x106 => WireErrorCode::FrameError,
0x107 => WireErrorCode::ExcessiveLoad,
0x108 => WireErrorCode::IdError,
0x109 => WireErrorCode::SettingsError,
0x10a => WireErrorCode::MissingSettings,
0x10b => WireErrorCode::RequestRejected,
0x10c => WireErrorCode::RequestCancelled,
0x10d => WireErrorCode::RequestIncomplete,
0x10e => WireErrorCode::MessageError,
0x10f => WireErrorCode::ConnectError,
0x110 => WireErrorCode::VersionFallback,
_ => return Err(FromWireConversionError::Unknown),
};

Ok(res)
}
}

impl Error {
fn to_wire(self) -> u64 {
match self {
Expand Down Expand Up @@ -6482,6 +6523,19 @@ mod tests {
assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
assert_eq!(s.poll_client(), Err(Error::Done));
}

#[test]
fn wire_error_convert() {
assert_eq!(WireErrorCode::try_from(0x100), Ok(WireErrorCode::NoError));
assert_eq!(
WireErrorCode::try_from(u64::MAX),
Err(FromWireConversionError::TooBig)
);
assert_eq!(
WireErrorCode::try_from(0),
Err(FromWireConversionError::Unknown)
);
}
}

#[cfg(feature = "ffi")]
Expand Down
63 changes: 63 additions & 0 deletions quiche/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ use qlog::events::RawInfo;
use stream::StreamPriorityKey;

use std::cmp;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::time;

Expand Down Expand Up @@ -643,6 +644,51 @@ pub enum WireErrorCode {
NoViablePath = 0x10,
}

/// Errors for conversions related to [WireErrorCode].
#[derive(Debug, Eq, PartialEq)]
pub enum FromWireConversionError {
/// The value was larger than the maximum encodable length.
TooBig,
/// The value was in the crypto error range.
CryptoRange,
/// The value was unknown by quiche, possibly a private extension or grease.
Unknown,
}

impl TryFrom<u64> for WireErrorCode {
type Error = FromWireConversionError;

fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
if value >= 1 << 62 {
return Err(FromWireConversionError::TooBig);
}

let res = match value {
0x0 => WireErrorCode::NoError,
0x1 => WireErrorCode::InternalError,
0x2 => WireErrorCode::ConnectionRefused,
0x3 => WireErrorCode::FlowControlError,
0x4 => WireErrorCode::StreamLimitError,
0x5 => WireErrorCode::StreamStateError,
0x6 => WireErrorCode::FinalSizeError,
0x7 => WireErrorCode::FrameEncodingError,
0x8 => WireErrorCode::TransportParameterError,
0x9 => WireErrorCode::ConnectionIdLimitError,
0xa => WireErrorCode::ProtocolViolation,
0xb => WireErrorCode::InvalidToken,
0xc => WireErrorCode::ApplicationError,
0xd => WireErrorCode::CryptoBufferExceeded,
0xe => WireErrorCode::KeyUpdateError,
0xf => WireErrorCode::AeadLimitReached,
0x10 => WireErrorCode::NoViablePath,
0x100..=0x1ff => return Err(FromWireConversionError::CryptoRange),
_ => return Err(FromWireConversionError::Unknown),
};

Ok(res)
}
}

impl Error {
fn to_wire(self) -> u64 {
match self {
Expand Down Expand Up @@ -17334,6 +17380,23 @@ mod tests {
// Continue searching for PMTU
assert!(pmtu_param.get_probe_status());
}

#[test]
fn wire_error_convert() {
assert_eq!(WireErrorCode::try_from(0), Ok(WireErrorCode::NoError));
assert_eq!(
WireErrorCode::try_from(u64::MAX),
Err(FromWireConversionError::TooBig)
);
assert_eq!(
WireErrorCode::try_from(0x100),
Err(FromWireConversionError::CryptoRange)
);
assert_eq!(
WireErrorCode::try_from(0x200),
Err(FromWireConversionError::Unknown)
);
}
}

pub use crate::packet::ConnectionId;
Expand Down

0 comments on commit 98963e6

Please sign in to comment.