in neqo-transport/src/connection/mod.rs [1387:1528]
fn preprocess_packet(
&mut self,
packet: &PublicPacket,
path: &PathRef,
dcid: Option<&ConnectionId>,
now: Instant,
) -> Res<PreprocessResult> {
if dcid.is_some_and(|d| d != &packet.dcid()) {
self.stats
.borrow_mut()
.pkt_dropped("Coalesced packet has different DCID");
return Ok(PreprocessResult::Next);
}
if (packet.packet_type() == PacketType::Initial
|| packet.packet_type() == PacketType::Handshake)
&& self.role == Role::Client
&& !path.borrow().is_primary()
{
// If we have received a packet from a different address than we have sent to
// we should ignore the packet. In such a case a path will be a newly created
// temporary path, not the primary path.
return Ok(PreprocessResult::Next);
}
match (packet.packet_type(), &self.state, &self.role) {
(PacketType::Initial, State::Init, Role::Server) => {
let version = packet.version().ok_or(Error::ProtocolViolation)?;
if !packet.is_valid_initial()
|| !self.conn_params.get_versions().all().contains(&version)
{
self.stats.borrow_mut().pkt_dropped("Invalid Initial");
return Ok(PreprocessResult::Next);
}
qinfo!(
"[{self}] Received valid Initial packet with scid {:?} dcid {:?}",
packet.scid(),
packet.dcid()
);
// Record the client's selected CID so that it can be accepted until
// the client starts using a real connection ID.
let dcid = ConnectionId::from(packet.dcid());
self.crypto.states.init_server(version, &dcid)?;
self.original_destination_cid = Some(dcid);
self.set_state(State::WaitInitial, now);
// We need to make sure that we set this transport parameter.
// This has to happen prior to processing the packet so that
// the TLS handshake has all it needs.
if !self.retry_sent() {
self.tps
.borrow_mut()
.local
.set_bytes(OriginalDestinationConnectionId, packet.dcid().to_vec());
}
}
(PacketType::VersionNegotiation, State::WaitInitial, Role::Client) => {
if let Ok(versions) = packet.supported_versions() {
if versions.is_empty()
|| versions.contains(&self.version().wire_version())
|| versions.contains(&0)
|| &packet.scid() != self.odcid().ok_or(Error::InternalError)?
|| matches!(self.address_validation, AddressValidationInfo::Retry { .. })
{
// Ignore VersionNegotiation packets that contain the current version.
// Or don't have the right connection ID.
// Or are received after a Retry.
self.stats.borrow_mut().pkt_dropped("Invalid VN");
} else {
self.version_negotiation(&versions, now)?;
}
} else {
self.stats.borrow_mut().pkt_dropped("VN with no versions");
}
return Ok(PreprocessResult::End);
}
(PacketType::Retry, State::WaitInitial, Role::Client) => {
self.handle_retry(packet, now)?;
return Ok(PreprocessResult::Next);
}
(PacketType::Handshake | PacketType::Short, State::WaitInitial, Role::Client) => {
// This packet can't be processed now, but it could be a sign
// that Initial packets were lost.
// Resend Initial CRYPTO frames immediately a few times just
// in case. As we don't have an RTT estimate yet, this helps
// when there is a short RTT and losses. Also mark all 0-RTT
// data as lost.
if dcid.is_none()
&& self.cid_manager.is_valid(packet.dcid())
&& self.stats.borrow().saved_datagrams <= EXTRA_INITIALS
{
self.crypto.resend_unacked(PacketNumberSpace::Initial);
self.resend_0rtt(now);
}
}
(PacketType::VersionNegotiation | PacketType::Retry | PacketType::OtherVersion, ..) => {
self.stats
.borrow_mut()
.pkt_dropped(format!("{:?}", packet.packet_type()));
return Ok(PreprocessResult::Next);
}
_ => {}
}
let res = match self.state {
State::Init => {
self.stats
.borrow_mut()
.pkt_dropped("Received while in Init state");
PreprocessResult::Next
}
State::WaitInitial => PreprocessResult::Continue,
State::WaitVersion | State::Handshaking | State::Connected | State::Confirmed => {
if self.cid_manager.is_valid(packet.dcid()) {
if self.role == Role::Server && packet.packet_type() == PacketType::Handshake {
// Server has received a Handshake packet -> discard Initial keys and states
self.discard_keys(PacketNumberSpace::Initial, now);
}
PreprocessResult::Continue
} else {
self.stats
.borrow_mut()
.pkt_dropped(format!("Invalid DCID {:?}", packet.dcid()));
PreprocessResult::Next
}
}
State::Closing { .. } => {
// Don't bother processing the packet. Instead ask to get a
// new close frame.
self.state_signaling.send_close();
PreprocessResult::Next
}
State::Draining { .. } | State::Closed(..) => {
// Do nothing.
self.stats
.borrow_mut()
.pkt_dropped(format!("State {:?}", self.state));
PreprocessResult::Next
}
};
Ok(res)
}