Skip to content

Commit

Permalink
Upgrade to Quinn 0.11
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed May 7, 2024
1 parent 60eef73 commit 2f0472f
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ env:
RUST_BACKTRACE: 1
toolchain_style: stable
toolchain_msrv: 1.63
toolchain_h3_quinn_msrv: 1.63
toolchain_h3_quinn_msrv: 1.66
toolchain_doc: nightly-2023-10-21
toolchain_lint: stable
toolchain_fuzz: nightly-2023-10-21
Expand Down
6 changes: 3 additions & 3 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ quinn = { version = "0.10", default-features = false, features = [
"tls-rustls",
"ring",
] }
rcgen = { version = "0.12" }
rustls = { version = "0.21", features = ["dangerous_configuration"] }
rustls-native-certs = "0.6"
rcgen = { version = "0.13" }
rustls = { version = "0.23", default-features = false, features = ["logging", "ring", "std"] }
rustls-native-certs = "0.7"
structopt = "0.3"
tokio = { version = "1.27", features = ["full"] }
tracing = "0.1.37"
Expand Down
12 changes: 6 additions & 6 deletions examples/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{path::PathBuf, sync::Arc};

use futures::future;
use rustls::pki_types::CertificateDer;
use structopt::StructOpt;
use tokio::io::AsyncWriteExt;
use tracing::{error, info};
Expand Down Expand Up @@ -64,7 +65,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match rustls_native_certs::load_native_certs() {
Ok(certs) => {
for cert in certs {
if let Err(e) = roots.add(&rustls::Certificate(cert.0)) {
if let Err(e) = roots.add(cert) {
error!("failed to parse trust anchor: {}", e);
}
}
Expand All @@ -76,14 +77,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

// load certificate of CA who issues the server certificate
// NOTE that this should be used for dev only
if let Err(e) = roots.add(&rustls::Certificate(std::fs::read(opt.ca)?)) {
if let Err(e) = roots.add(CertificateDer::from(std::fs::read(opt.ca)?)) {
error!("failed to parse trust anchor: {}", e);
}

let mut tls_config = rustls::ClientConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])?
.with_root_certificates(roots)
.with_no_client_auth();

Expand All @@ -99,7 +97,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

let mut client_endpoint = h3_quinn::quinn::Endpoint::client("[::]:0".parse().unwrap())?;

let client_config = quinn::ClientConfig::new(Arc::new(tls_config));
let client_config = quinn::ClientConfig::new(Arc::new(
quinn::crypto::rustls::QuicClientConfig::try_from(tls_config)?,
));
client_endpoint.set_default_client_config(client_config);

let conn = client_endpoint.connect(addr, auth.host())?.await?;
Expand Down
15 changes: 6 additions & 9 deletions examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc};

use bytes::{Bytes, BytesMut};
use http::{Request, StatusCode};
use rustls::{Certificate, PrivateKey};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use structopt::StructOpt;
use tokio::{fs::File, io::AsyncReadExt};
use tracing::{error, info, trace_span};

use h3::{error::ErrorLevel, quic::BidiStream, server::RequestStream};
use h3_quinn::quinn;
use h3_quinn::quinn::{self, crypto::rustls::QuicServerConfig};

#[derive(StructOpt, Debug)]
#[structopt(name = "server")]
Expand Down Expand Up @@ -84,21 +84,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// create quinn server endpoint and bind UDP socket

// both cert and key must be DER-encoded
let cert = Certificate(std::fs::read(cert)?);
let key = PrivateKey(std::fs::read(key)?);
let cert = CertificateDer::from(std::fs::read(cert)?);
let key = PrivateKeyDer::try_from(std::fs::read(key)?)?;

let mut tls_config = rustls::ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_no_client_auth()
.with_single_cert(vec![cert], key)?;

tls_config.max_early_data_size = u32::MAX;
tls_config.alpn_protocols = vec![ALPN.into()];

let server_config = quinn::ServerConfig::with_crypto(Arc::new(tls_config));
let server_config =
quinn::ServerConfig::with_crypto(Arc::new(QuicServerConfig::try_from(tls_config)?));
let endpoint = quinn::Endpoint::server(server_config, opt.listen)?;

info!("listening on {}", opt.listen);
Expand Down
15 changes: 6 additions & 9 deletions examples/webtransport_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use h3::{
quic::{self, RecvDatagramExt, SendDatagramExt, SendStreamUnframed},
server::Connection,
};
use h3_quinn::quinn;
use h3_quinn::quinn::{self, crypto::rustls::QuicServerConfig};
use h3_webtransport::{
server::{self, WebTransportSession},
stream,
};
use http::Method;
use rustls::{Certificate, PrivateKey};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
use structopt::StructOpt;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
Expand Down Expand Up @@ -81,14 +81,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// create quinn server endpoint and bind UDP socket

// both cert and key must be DER-encoded
let cert = Certificate(std::fs::read(cert)?);
let key = PrivateKey(std::fs::read(key)?);
let cert = CertificateDer::from(std::fs::read(cert)?);
let key = PrivateKeyDer::try_from(std::fs::read(key)?)?;

let mut tls_config = rustls::ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_no_client_auth()
.with_single_cert(vec![cert], key)?;

Expand All @@ -102,7 +98,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
];
tls_config.alpn_protocols = alpn;

let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(tls_config));
let mut server_config =
quinn::ServerConfig::with_crypto(Arc::new(QuicServerConfig::try_from(tls_config)?));
let mut transport_config = quinn::TransportConfig::default();
transport_config.keep_alive_interval(Some(Duration::from_secs(2)));
server_config.transport = Arc::new(transport_config);
Expand Down
4 changes: 2 additions & 2 deletions h3-quinn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "h3-quinn"
version = "0.0.5"
rust-version = "1.63"
rust-version = "1.66"
authors = ["Jean-Christophe BEGUE <[email protected]>"]
edition = "2021"
documentation = "https://docs.rs/h3-quinn"
Expand All @@ -15,7 +15,7 @@ license = "MIT"
[dependencies]
h3 = { version = "0.0.4", path = "../h3" }
bytes = "1"
quinn = { version = "0.10", default-features = false, features = [
quinn = { version = "0.11", default-features = false, features = [
"futures-io",
] }
tokio-util = { version = "0.7.9" }
Expand Down
19 changes: 12 additions & 7 deletions h3-quinn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use futures::{
StreamExt,
};
pub use quinn::{self, AcceptBi, AcceptUni, Endpoint, OpenBi, OpenUni, VarInt, WriteError};
use quinn::{ApplicationClose, ReadDatagram};
use quinn::{ApplicationClose, ClosedStream, ReadDatagram};

use h3::{
ext::Datagram,
Expand Down Expand Up @@ -592,12 +592,8 @@ where
Poll::Ready(Ok(()))
}

fn poll_finish(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
self.stream
.as_mut()
.unwrap()
.poll_finish(cx)
.map_err(Into::into)
fn poll_finish(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(self.stream.as_mut().unwrap().finish().map_err(|e| e.into()))
}

fn reset(&mut self, reset_code: u64) {
Expand Down Expand Up @@ -679,6 +675,8 @@ pub enum SendStreamError {
/// Error when the stream is not ready, because it is still sending
/// data from a previous call
NotReady,
/// Error when the stream is closed
StreamClosed(ClosedStream),
}

impl From<SendStreamError> for std::io::Error {
Expand All @@ -688,6 +686,7 @@ impl From<SendStreamError> for std::io::Error {
SendStreamError::NotReady => {
std::io::Error::new(std::io::ErrorKind::Other, "send stream is not ready")
}
SendStreamError::StreamClosed(err) => err.into(),
}
}
}
Expand All @@ -706,6 +705,12 @@ impl From<WriteError> for SendStreamError {
}
}

impl From<ClosedStream> for SendStreamError {
fn from(value: ClosedStream) -> Self {
Self::StreamClosed(value)
}
}

impl Error for SendStreamError {
fn is_timeout(&self) -> bool {
matches!(
Expand Down
10 changes: 5 additions & 5 deletions h3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ fastrand = "2.0.1"
assert_matches = "1.5.0"
futures-util = { version = "0.3", default-features = false, features = ["io"] }
proptest = "1"
quinn = { version = "0.10", default-features = false, features = [
quinn = { version = "0.11", default-features = false, features = [
"runtime-tokio",
"tls-rustls",
"rustls",
"ring",
] }
quinn-proto = { version = "0.10", default-features = false }
rcgen = "0.12"
rustls = "0.21"
quinn-proto = { version = "0.11", default-features = false }
rcgen = "0.13"
rustls = { version = "0.23", default-features = false, features = ["logging", "ring", "std"] }
tokio = { version = "1", features = ["rt", "macros", "io-util", "io-std"] }
tracing-subscriber = { version = "0.3", default-features = false, features = [
"fmt",
Expand Down
4 changes: 2 additions & 2 deletions h3/src/tests/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ async fn control_close_send_error() {
//# If either control
//# stream is closed at any point, this MUST be treated as a connection
//# error of type H3_CLOSED_CRITICAL_STREAM.
control_stream.finish().await.unwrap(); // close the client control stream immediately
control_stream.finish().unwrap(); // close the client control stream immediately

// create the Connection manually so it does not open a second Control stream

Expand Down Expand Up @@ -533,7 +533,7 @@ async fn goaway_from_server_not_request_id() {
let mut buf = BytesMut::new();
StreamType::CONTROL.encode(&mut buf);
control_stream.write_all(&buf[..]).await.unwrap();
control_stream.finish().await.unwrap(); // close the client control stream immediately
control_stream.finish().unwrap(); // close the client control stream immediately

let (mut driver, _send) = client::new(h3_quinn::Connection::new(connection))
.await
Expand Down
57 changes: 31 additions & 26 deletions h3/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use std::{
};

use bytes::Bytes;
use rustls::{Certificate, PrivateKey};
use quinn::crypto::rustls::{QuicClientConfig, QuicServerConfig};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};

use crate::quic;
use h3_quinn::{quinn::TransportConfig, Connection};
Expand All @@ -32,11 +33,10 @@ pub fn init_tracing() {
.try_init();
}

#[derive(Clone)]
pub struct Pair {
port: u16,
cert: Certificate,
key: PrivateKey,
cert: CertificateDer<'static>,
key: PrivateKeyDer<'static>,
config: Arc<TransportConfig>,
}

Expand All @@ -63,18 +63,20 @@ impl Pair {
}

pub fn server_inner(&mut self) -> h3_quinn::Endpoint {
let mut crypto = rustls::ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_no_client_auth()
.with_single_cert(vec![self.cert.clone()], self.key.clone())
.unwrap();
let mut crypto = rustls::ServerConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_no_client_auth()
.with_single_cert(vec![self.cert.clone()], self.key.clone_key())
.unwrap();
crypto.max_early_data_size = u32::MAX;
crypto.alpn_protocols = vec![b"h3".to_vec()];

let mut server_config = h3_quinn::quinn::ServerConfig::with_crypto(Arc::new(crypto));
let mut server_config = h3_quinn::quinn::ServerConfig::with_crypto(Arc::new(
QuicServerConfig::try_from(crypto).unwrap(),
));
server_config.transport = self.config.clone();
let endpoint =
h3_quinn::quinn::Endpoint::server(server_config, "[::]:0".parse().unwrap()).unwrap();
Expand All @@ -97,18 +99,20 @@ impl Pair {
.unwrap();

let mut root_cert_store = rustls::RootCertStore::empty();
root_cert_store.add(&self.cert).unwrap();
let mut crypto = rustls::ClientConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_root_certificates(root_cert_store)
.with_no_client_auth();
root_cert_store.add(self.cert.clone()).unwrap();
let mut crypto = rustls::ClientConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap()
.with_root_certificates(root_cert_store)
.with_no_client_auth();
crypto.enable_early_data = true;
crypto.alpn_protocols = vec![b"h3".to_vec()];

let client_config = h3_quinn::quinn::ClientConfig::new(Arc::new(crypto));
let client_config = h3_quinn::quinn::ClientConfig::new(Arc::new(
QuicClientConfig::try_from(crypto).unwrap(),
));

let mut client_endpoint =
h3_quinn::quinn::Endpoint::client("[::]:0".parse().unwrap()).unwrap();
Expand All @@ -135,9 +139,10 @@ impl Server {
}
}

pub fn build_certs() -> (Certificate, PrivateKey) {
pub fn build_certs() -> (CertificateDer<'static>, PrivateKeyDer<'static>) {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
let key = PrivateKey(cert.serialize_private_key_der());
let cert = Certificate(cert.serialize_der().unwrap());
(cert, key)
(
cert.cert.into(),
PrivateKeyDer::Pkcs8(cert.key_pair.serialize_der().into()),
)
}
2 changes: 1 addition & 1 deletion h3/src/tests/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ where
let mut buf = BytesMut::new();
request(&mut buf);
req_send.write_all(&buf[..]).await.unwrap();
req_send.finish().await.unwrap();
req_send.finish().unwrap();

let res = req_recv
.read(&mut buf)
Expand Down

0 comments on commit 2f0472f

Please sign in to comment.