in neqo-transport/src/connection/mod.rs [2806:2858]
fn validate_versions(&self) -> Res<()> {
let tph = self.tps.borrow();
let remote_tps = tph.remote.as_ref().ok_or(Error::TransportParameterError)?;
// `current` and `other` are the value from the peer's transport parameters.
// We're checking that these match our expectations.
if let Some((current, other)) = remote_tps.get_versions() {
qtrace!(
"[{self}] validate_versions: current={:x} chosen={current:x} other={other:x?}",
self.version.wire_version(),
);
if self.role == Role::Server {
// 1. A server acts on transport parameters, with validation
// of `current` happening in the transport parameter handler.
// All we need to do is confirm that the transport parameter
// was provided.
Ok(())
} else if self.version().wire_version() != current {
qinfo!("[{self}] validate_versions: current version mismatch");
Err(Error::VersionNegotiation)
} else if self
.conn_params
.get_versions()
.initial()
.is_compatible(self.version)
{
// 2. The current version is compatible with what we attempted.
// That's a compatible upgrade and that's OK.
Ok(())
} else {
// 3. The initial version we attempted isn't compatible. Check that
// the one we would have chosen is compatible with this one.
let mut all_versions = other.to_owned();
all_versions.push(current);
if self
.conn_params
.get_versions()
.preferred(&all_versions)
.ok_or(Error::VersionNegotiation)?
.is_compatible(self.version)
{
Ok(())
} else {
qinfo!("[{self}] validate_versions: failed");
Err(Error::VersionNegotiation)
}
}
} else if self.version != Version::Version1 && !self.version.is_draft() {
qinfo!("[{self}] validate_versions: missing extension");
Err(Error::VersionNegotiation)
} else {
Ok(())
}
}