pub const QUIC_VERSION_NEGOTIATION: u32 = 0x0000_0000;
pub const QUIC_VERSION_1: u32 = 0x0000_0001;
pub const QUIC_VERSION_2: u32 = 0x6b33_43cf;
pub const QUIC_VERSION_GOOGLE_Q043: u32 = 0x5130_3433;
pub const QUIC_VERSION_GOOGLE_Q046: u32 = 0x5130_3436;
pub const QUIC_VERSION_GOOGLE_Q050: u32 = 0x5130_3530;
pub const QUIC_VERSION_2_DRAFT: u32 = 0x709a_50c4;
pub const QUIC_VERSION_SCONE_EVEN_SIGNAL: u32 = 0x6f7d_c0fd;
pub const QUIC_VERSION_SCONE_ODD_SIGNAL: u32 = 0xef7d_c0fd;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum QuicVersionStatus {
VersionNegotiation,
Permanent,
ReservedGrease,
Provisional,
Unknown,
}
pub const fn is_quic_grease_version(version: u32) -> bool {
(version & 0x0f0f_0f0f) == 0x0a0a_0a0a
}
pub const fn is_quic_default_version(version: u32) -> bool {
matches!(version, QUIC_VERSION_1 | QUIC_VERSION_2)
}
pub const fn quic_version_status(version: u32) -> QuicVersionStatus {
match version {
QUIC_VERSION_NEGOTIATION => QuicVersionStatus::VersionNegotiation,
QUIC_VERSION_1 | QUIC_VERSION_2 => QuicVersionStatus::Permanent,
QUIC_VERSION_GOOGLE_Q043
| QUIC_VERSION_GOOGLE_Q046
| QUIC_VERSION_GOOGLE_Q050
| QUIC_VERSION_2_DRAFT
| QUIC_VERSION_SCONE_EVEN_SIGNAL
| QUIC_VERSION_SCONE_ODD_SIGNAL => QuicVersionStatus::Provisional,
_ if is_quic_grease_version(version) => QuicVersionStatus::ReservedGrease,
_ => QuicVersionStatus::Unknown,
}
}
pub const fn quic_version_name(version: u32) -> Option<&'static str> {
match version {
QUIC_VERSION_NEGOTIATION => Some("Version Negotiation"),
QUIC_VERSION_1 => Some("QUIC v1"),
QUIC_VERSION_2 => Some("QUIC v2"),
QUIC_VERSION_GOOGLE_Q043 => Some("Google QUIC Q043"),
QUIC_VERSION_GOOGLE_Q046 => Some("Google QUIC Q046"),
QUIC_VERSION_GOOGLE_Q050 => Some("Google QUIC Q050"),
QUIC_VERSION_2_DRAFT => Some("QUIC v2 draft"),
QUIC_VERSION_SCONE_EVEN_SIGNAL => Some("SCONE even signal"),
QUIC_VERSION_SCONE_ODD_SIGNAL => Some("SCONE odd signal"),
_ => None,
}
}
pub fn quic_version_label(version: u32) -> String {
if let Some(name) = quic_version_name(version) {
return name.to_string();
}
if is_quic_grease_version(version) {
return format!("reserved grease version 0x{version:08x}");
}
format!("unknown version 0x{version:08x}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn quic_version_constants_classify_default_versions() {
assert_eq!(
quic_version_status(QUIC_VERSION_NEGOTIATION),
QuicVersionStatus::VersionNegotiation
);
assert_eq!(
quic_version_status(QUIC_VERSION_1),
QuicVersionStatus::Permanent
);
assert_eq!(
quic_version_status(QUIC_VERSION_2),
QuicVersionStatus::Permanent
);
assert!(is_quic_default_version(QUIC_VERSION_1));
assert!(is_quic_default_version(QUIC_VERSION_2));
assert!(!is_quic_default_version(QUIC_VERSION_NEGOTIATION));
}
#[test]
fn quic_version_constants_classify_provisional_rows() {
for version in [
QUIC_VERSION_GOOGLE_Q043,
QUIC_VERSION_GOOGLE_Q046,
QUIC_VERSION_GOOGLE_Q050,
QUIC_VERSION_2_DRAFT,
QUIC_VERSION_SCONE_EVEN_SIGNAL,
QUIC_VERSION_SCONE_ODD_SIGNAL,
] {
assert_eq!(quic_version_status(version), QuicVersionStatus::Provisional);
assert!(!is_quic_default_version(version));
}
}
#[test]
fn quic_version_constants_classify_grease_and_unknown_values() {
assert!(is_quic_grease_version(0x0a0a_0a0a));
assert!(is_quic_grease_version(0x1a2a_3a4a));
assert_eq!(
quic_version_status(0x0a0a_0a0a),
QuicVersionStatus::ReservedGrease
);
assert_eq!(quic_version_status(0xface_feed), QuicVersionStatus::Unknown);
}
#[test]
fn quic_version_constants_labels_known_and_numeric_values() {
assert_eq!(quic_version_name(QUIC_VERSION_1), Some("QUIC v1"));
assert_eq!(quic_version_label(QUIC_VERSION_2), "QUIC v2");
assert_eq!(
quic_version_label(0x0a0a_0a0a),
"reserved grease version 0x0a0a0a0a"
);
assert_eq!(
quic_version_label(0xface_feed),
"unknown version 0xfacefeed"
);
}
}