Skip to content

Commit bf3219e

Browse files
committed
Fix panic on multiple incoming connections w/ zero-length IDs
1 parent 774e289 commit bf3219e

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

quinn-proto/src/endpoint.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,15 @@ impl Endpoint {
457457
fn new_cid(&mut self, ch: ConnectionHandle) -> ConnectionId {
458458
loop {
459459
let cid = self.local_cid_generator.generate_cid();
460+
if cid.len() == 0 {
461+
// Zero-length CID; nothing to track
462+
debug_assert_eq!(self.local_cid_generator.cid_len(), 0);
463+
return cid;
464+
}
460465
if let hash_map::Entry::Vacant(e) = self.index.connection_ids.entry(cid) {
461466
e.insert(ch);
462467
break cid;
463468
}
464-
assert!(self.local_cid_generator.cid_len() > 0);
465469
}
466470
}
467471

quinn/src/tests.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{
1010

1111
use crate::runtime::TokioRuntime;
1212
use bytes::Bytes;
13-
use proto::crypto::rustls::QuicClientConfig;
13+
use proto::{crypto::rustls::QuicClientConfig, RandomConnectionIdGenerator};
1414
use rand::{rngs::StdRng, RngCore, SeedableRng};
1515
use rustls::{
1616
pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer},
@@ -266,12 +266,14 @@ fn endpoint_with_config(transport_config: TransportConfig) -> Endpoint {
266266
/// Constructs endpoints suitable for connecting to themselves and each other
267267
struct EndpointFactory {
268268
cert: rcgen::CertifiedKey,
269+
endpoint_config: EndpointConfig,
269270
}
270271

271272
impl EndpointFactory {
272273
fn new() -> Self {
273274
Self {
274275
cert: rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(),
276+
endpoint_config: EndpointConfig::default(),
275277
}
276278
}
277279

@@ -289,7 +291,7 @@ impl EndpointFactory {
289291
let mut roots = rustls::RootCertStore::empty();
290292
roots.add(self.cert.cert.der().clone()).unwrap();
291293
let mut endpoint = Endpoint::new(
292-
EndpointConfig::default(),
294+
self.endpoint_config.clone(),
293295
Some(server_config),
294296
UdpSocket::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0)).unwrap(),
295297
Arc::new(TokioRuntime),
@@ -809,3 +811,54 @@ async fn two_datagram_readers() {
809811
assert!(*a == *b"one" || *b == *b"one");
810812
assert!(*a == *b"two" || *b == *b"two");
811813
}
814+
815+
#[tokio::test]
816+
async fn multiple_conns_with_zero_length_cids() {
817+
let _guard = subscribe();
818+
let mut factory = EndpointFactory::new();
819+
factory
820+
.endpoint_config
821+
.cid_generator(|| Box::new(RandomConnectionIdGenerator::new(0)));
822+
let server = {
823+
let _guard = error_span!("server").entered();
824+
factory.endpoint()
825+
};
826+
let server_addr = server.local_addr().unwrap();
827+
828+
let client1 = {
829+
let _guard = error_span!("client1").entered();
830+
factory.endpoint()
831+
};
832+
let client2 = {
833+
let _guard = error_span!("client2").entered();
834+
factory.endpoint()
835+
};
836+
837+
let client1 = async move {
838+
let conn = client1
839+
.connect(server_addr, "localhost")
840+
.unwrap()
841+
.await
842+
.unwrap();
843+
conn.closed().await;
844+
}
845+
.instrument(error_span!("client1"));
846+
let client2 = async move {
847+
let conn = client2
848+
.connect(server_addr, "localhost")
849+
.unwrap()
850+
.await
851+
.unwrap();
852+
conn.closed().await;
853+
}
854+
.instrument(error_span!("client2"));
855+
let server = async move {
856+
let client1 = server.accept().await.unwrap().await.unwrap();
857+
let client2 = server.accept().await.unwrap().await.unwrap();
858+
// Both connections are now concurrently live.
859+
client1.close(42u32.into(), &[]);
860+
client2.close(42u32.into(), &[]);
861+
}
862+
.instrument(error_span!("server"));
863+
tokio::join!(client1, client2, server);
864+
}

0 commit comments

Comments
 (0)