Skip to content

Commit 5ceed19

Browse files
committed
docs and tests
1 parent 132ceb7 commit 5ceed19

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

quinn/src/connection.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ impl Connection {
518518
.clone()
519519
}
520520

521-
/// Wait for the connection to be closed without keeping a strong reference to the connection.
521+
/// Wait for the connection to be closed without keeping a strong reference to the connection
522522
///
523523
/// Calling [`Self::closed`] keeps the connection alive until it is either closed locally via [`Connection::close`]
524524
/// or closed by the remote peer. This function instead does not keep a reference to the connection itself,
@@ -1061,6 +1061,7 @@ struct OnClosed {
10611061
conn: WeakConnectionHandle,
10621062
}
10631063

1064+
/// Future returned by [`Connection::on_closed`]
10641065
impl Drop for OnClosed {
10651066
fn drop(&mut self) {
10661067
if self.rx.is_terminated() {
@@ -1082,9 +1083,11 @@ impl Future for OnClosed {
10821083

10831084
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
10841085
let this = self.get_mut();
1086+
// The `expect` is safe because `State::drop` ensures that all senders are triggered
1087+
// before being dropped.
10851088
Pin::new(&mut this.rx)
10861089
.poll(cx)
1087-
.map(|x| x.expect("sender is never dropped before sending"))
1090+
.map(|x| x.expect("on_clone sender is never dropped before sending"))
10881091
}
10891092
}
10901093

@@ -1569,6 +1572,7 @@ impl Drop for State {
15691572
}
15701573

15711574
if !self.on_closed.is_empty() {
1575+
// Ensure that all on_closed oneshot senders are triggered before dropping.
15721576
let reason = self.error.as_ref().expect("closed without error reason");
15731577
let stats = self.inner.stats();
15741578
for tx in self.on_closed.drain(..) {

quinn/src/tests.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,3 +1061,52 @@ async fn on_closed() {
10611061
server_res.expect("server task panicked");
10621062
client_res.expect("client task panicked");
10631063
}
1064+
1065+
#[tokio::test]
1066+
async fn on_closed_endpoint_drop() {
1067+
let _guard = subscribe();
1068+
let factory = EndpointFactory::new();
1069+
let client = factory.endpoint("client");
1070+
let server = factory.endpoint("server");
1071+
let server_addr = server.local_addr().unwrap();
1072+
let server_task = tokio::time::timeout(
1073+
Duration::from_millis(500),
1074+
tokio::spawn(async move {
1075+
let conn = server
1076+
.accept()
1077+
.await
1078+
.expect("endpoint")
1079+
.await
1080+
.expect("accept");
1081+
println!("accepted");
1082+
let on_closed = conn.on_closed();
1083+
drop(conn);
1084+
drop(server);
1085+
let (cause, _stats) = on_closed.await;
1086+
assert!(matches!(cause, ConnectionError::ApplicationClosed(_)));
1087+
}),
1088+
);
1089+
let client_task = tokio::time::timeout(
1090+
Duration::from_millis(500),
1091+
tokio::spawn(async move {
1092+
let conn = client
1093+
.connect(server_addr, "localhost")
1094+
.unwrap()
1095+
.await
1096+
.expect("connect");
1097+
println!("connected");
1098+
let on_closed = conn.on_closed();
1099+
drop(conn);
1100+
drop(client);
1101+
let (cause, _stats) = on_closed.await;
1102+
assert_eq!(cause, ConnectionError::LocallyClosed);
1103+
}),
1104+
);
1105+
let (server_res, client_res) = tokio::join!(server_task, client_task);
1106+
server_res
1107+
.expect("server timeout")
1108+
.expect("server task panicked");
1109+
client_res
1110+
.expect("client timeout")
1111+
.expect("client task panicked");
1112+
}

0 commit comments

Comments
 (0)