Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 13 additions & 26 deletions noq-proto/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2421,13 +2421,7 @@ impl Connection {
match timer {
Timer::Conn(timer) => match timer {
ConnTimer::Close => {
let was_draining = self.state.move_to_drained(None);
if !was_draining {
self.endpoint_events.push_back(EndpointEventInner::Draining);
}
// move_to_drained checks that we weren't in drained before.
// Adding events to endpoint_events is only legal if `Drained` was never queued before.
self.endpoint_events.push_back(EndpointEventInner::Drained);
self.state.move_to_drained(None, &mut self.endpoint_events);
}
ConnTimer::Idle => {
self.kill(ConnectionError::TimedOut);
Expand Down Expand Up @@ -4407,9 +4401,9 @@ impl Connection {
code: TransportErrorCode::AEAD_LIMIT_REACHED,
..
}) => {
let was_draining = self.state.move_to_drained(Some(conn_err));
if !was_draining && !was_drained {
self.endpoint_events.push_back(EndpointEventInner::Draining);
if !self.state.is_drained() {
self.state
.move_to_drained(Some(conn_err), &mut self.endpoint_events);
}
}
ConnectionError::TimedOut => {
Expand All @@ -4420,8 +4414,8 @@ impl Connection {
self.state.move_to_closed(err);
}
ConnectionError::VersionMismatch => {
self.state.move_to_draining(Some(conn_err));
self.endpoint_events.push_back(EndpointEventInner::Draining);
self.state
.move_to_draining(Some(conn_err), &mut self.endpoint_events);
}
ConnectionError::LocallyClosed => {
unreachable!("LocallyClosed isn't generated by packet processing");
Expand All @@ -4439,7 +4433,6 @@ impl Connection {
}
}
if !was_drained && self.state.is_drained() {
self.endpoint_events.push_back(EndpointEventInner::Drained);
// Close timer may have been started previously, e.g. if we sent a close and got a
// stateless reset in response
self.timers
Expand Down Expand Up @@ -4537,8 +4530,7 @@ impl Connection {
self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());

if let Frame::Close(_error) = frame {
self.state.move_to_draining(None);
self.endpoint_events.push_back(EndpointEventInner::Draining);
self.state.move_to_draining(None, &mut self.endpoint_events);
break;
}
}
Expand Down Expand Up @@ -4864,8 +4856,8 @@ impl Connection {
self.on_path_ack_received(now, packet.header.space().into(), ack)?;
}
Frame::Close(reason) => {
self.state.move_to_draining(Some(reason.into()));
self.endpoint_events.push_back(EndpointEventInner::Draining);
self.state
.move_to_draining(Some(reason.into()), &mut self.endpoint_events);
return Ok(());
}
_ => {
Expand Down Expand Up @@ -5549,8 +5541,8 @@ impl Connection {
self.streams.queue_max_stream_id(pending);

if let Some(reason) = close {
self.state.move_to_draining(Some(reason.into()));
self.endpoint_events.push_back(EndpointEventInner::Draining);
self.state
.move_to_draining(Some(reason.into()), &mut self.endpoint_events);
self.connection_close_pending = true;
}

Expand Down Expand Up @@ -6972,13 +6964,8 @@ impl Connection {
/// Terminate the connection instantly, without sending a close packet
fn kill(&mut self, reason: ConnectionError) {
self.close_common();
let was_draining = self.state.move_to_drained(Some(reason));
if !was_draining {
self.endpoint_events.push_back(EndpointEventInner::Draining);
}
// move_to_drained checks that we were never in drained before, so we
// never sent a `Drained` event before (it's illegal to send more events after drained).
self.endpoint_events.push_back(EndpointEventInner::Drained);
self.state
.move_to_drained(Some(reason), &mut self.endpoint_events);
}

/// Storage size required for the largest packet that can be transmitted on all currently
Expand Down
24 changes: 20 additions & 4 deletions noq-proto/src/connection/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bytes::Bytes;
use tracing::trace;

use crate::frame::Close;
use crate::shared::EndpointEventInner;
use crate::{ApplicationClose, ConnectionClose, ConnectionError, TransportError, TransportErrorCode};

#[allow(unreachable_pub)] // fuzzing only
Expand Down Expand Up @@ -67,8 +68,12 @@ impl State {
///
/// Panics if the state was already drained.
///
/// Returns whether we were in the draining state before.
pub(super) fn move_to_drained(&mut self, error: Option<ConnectionError>) -> bool {
/// Emits the appropriate `Draining` and `Drained` endpoint events into `events`.
pub(super) fn move_to_drained(
&mut self,
error: Option<ConnectionError>,
events: &mut impl Extend<EndpointEventInner>,
) {
let (error, is_local, was_draining) = if let Some(error) = error {
(
Some(error),
Expand Down Expand Up @@ -103,13 +108,23 @@ impl State {
};
self.inner = InnerState::Drained { error, is_local };
trace!("connection state: drained");
was_draining

if !was_draining {
events.extend([EndpointEventInner::Draining]);
}
events.extend([EndpointEventInner::Drained]);
}

/// Moves to a draining state.
///
/// Panics if the state is already draining or drained.
pub(super) fn move_to_draining(&mut self, error: Option<ConnectionError>) {
///
/// Emits a `Draining` endpoint event into `events`.
pub(super) fn move_to_draining(
&mut self,
error: Option<ConnectionError>,
events: &mut impl Extend<EndpointEventInner>,
) {
assert!(
matches!(
self.inner,
Expand Down Expand Up @@ -139,6 +154,7 @@ impl State {

self.inner = InnerState::Draining { error, is_local };
trace!("connection state: draining");
events.extend([EndpointEventInner::Draining]);
}

fn is_local_close(&self) -> bool {
Expand Down
Loading