Files
noq/quinn/examples/common/mod.rs
T
Benjamin Saunders 1e5a538221 Limit concurrent streams rather than accept queue size
Previously, we limited the number of streams that could be opened by
the peer but not `accept`ed by the application. However, to guarantee
bounded resource use, applications will typically want to limit the
number of streams they process concurrently. While this could
be *approximately* implemented at the application layer by controlling
calls to accept, that approach has a significant drawback: If streams
are slow to process, the worst-case per-stream latency observed by a
peer who opens the maximum number of streams can be arbitrarily bad,
because streams may be opened above the limit the local application is
willing to process. Reducing the number of unaccepted streams
tolerated can reduce the proportion of streams affected, but reducing
it too low will increase the number of round trips required to open
any given number of streams, increasing average latency significantly.

As a side benefit, this reduces the effort needed for applications to
limit concurrency to a fixed quantity, which is expected to be the
overwhelmingly common case. Should a use case for dynamic concurrency
limits arise, we can expose a setter.
2021-01-22 11:39:00 -08:00

77 lines
2.8 KiB
Rust

#![cfg(feature = "rustls")]
//! Commonly used code in most examples.
use quinn::{
Certificate, CertificateChain, ClientConfig, ClientConfigBuilder, Endpoint, Incoming,
PrivateKey, ServerConfig, ServerConfigBuilder, TransportConfig,
};
use std::{error::Error, net::SocketAddr, sync::Arc};
/// Constructs a QUIC endpoint configured for use a client only.
///
/// ## Args
///
/// - server_certs: list of trusted certificates.
#[allow(unused)]
pub fn make_client_endpoint(
bind_addr: SocketAddr,
server_certs: &[&[u8]],
) -> Result<Endpoint, Box<dyn Error>> {
let client_cfg = configure_client(server_certs)?;
let mut endpoint_builder = Endpoint::builder();
endpoint_builder.default_client_config(client_cfg);
let (endpoint, _incoming) = endpoint_builder.bind(&bind_addr)?;
Ok(endpoint)
}
/// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address
/// and port.
///
/// ## Returns
///
/// - a stream of incoming QUIC connections
/// - server certificate serialized into DER format
#[allow(unused)]
pub fn make_server_endpoint(bind_addr: SocketAddr) -> Result<(Incoming, Vec<u8>), Box<dyn Error>> {
let (server_config, server_cert) = configure_server()?;
let mut endpoint_builder = Endpoint::builder();
endpoint_builder.listen(server_config);
let (_endpoint, incoming) = endpoint_builder.bind(&bind_addr)?;
Ok((incoming, server_cert))
}
/// Builds default quinn client config and trusts given certificates.
///
/// ## Args
///
/// - server_certs: a list of trusted certificates in DER format.
fn configure_client(server_certs: &[&[u8]]) -> Result<ClientConfig, Box<dyn Error>> {
let mut cfg_builder = ClientConfigBuilder::default();
for cert in server_certs {
cfg_builder.add_certificate_authority(Certificate::from_der(&cert)?)?;
}
Ok(cfg_builder.build())
}
/// Returns default server configuration along with its certificate.
#[allow(clippy::field_reassign_with_default)] // https://github.com/rust-lang/rust-clippy/issues/6527
fn configure_server() -> Result<(ServerConfig, Vec<u8>), Box<dyn Error>> {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
let cert_der = cert.serialize_der().unwrap();
let priv_key = cert.serialize_private_key_der();
let priv_key = PrivateKey::from_der(&priv_key)?;
let mut transport_config = TransportConfig::default();
transport_config.max_concurrent_uni_streams(0).unwrap();
let mut server_config = ServerConfig::default();
server_config.transport = Arc::new(transport_config);
let mut cfg_builder = ServerConfigBuilder::new(server_config);
let cert = Certificate::from_der(&cert_der)?;
cfg_builder.certificate(CertificateChain::from_certs(vec![cert]), priv_key)?;
Ok((cfg_builder.build(), cert_der))
}
#[allow(unused)]
pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];