Convert Figma logo to code with AI

quinn-rs logoquinn

Async-friendly QUIC implementation in Rust

3,719
378
3,719
103

Top Related Projects

26,366

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

14,343

An HTTP library for Rust

9,488

A super-easy, composable, web server framework for warp speeds.

6,269

Metal I/O library for Rust.

Quick Overview

Quinn is a Rust implementation of the QUIC network protocol, which is a modern, secure, and efficient alternative to the traditional TCP/IP protocol. It aims to provide a high-performance, low-latency, and reliable transport layer for a wide range of applications, including web browsing, video streaming, and real-time communication.

Pros

  • High Performance: Quinn is designed to be highly efficient, with low latency and high throughput, making it suitable for a wide range of applications.
  • Secure: QUIC is built on top of TLS, providing end-to-end encryption and authentication, which helps to improve the overall security of network communications.
  • Reliable: QUIC includes features like reliable data delivery, stream multiplexing, and congestion control, which help to ensure reliable and stable connections.
  • Cross-Platform: Quinn is written in Rust, which allows it to be easily ported to a variety of platforms, including desktop, mobile, and server environments.

Cons

  • Complexity: The QUIC protocol is relatively new and complex, which can make it more challenging to understand and implement compared to traditional TCP/IP.
  • Limited Adoption: While QUIC is gaining traction, it is still not as widely adopted as TCP/IP, which can make it more difficult to integrate with existing systems and infrastructure.
  • Dependency on Rust: Since Quinn is written in Rust, it may be less accessible to developers who are more familiar with other programming languages, such as Python or Java.
  • Ongoing Development: As a relatively new project, Quinn is still under active development, which means that the API and functionality may change over time, potentially requiring more maintenance and updates.

Code Examples

Here are a few examples of how to use the Quinn library in Rust:

  1. Establishing a QUIC connection:
use quinn::{Endpoint, NewConnection, ServerConfig, TransportConfig};

async fn connect() -> Result<NewConnection, quinn::Error> {
    let mut endpoint = Endpoint::builder();
    endpoint.default_client_config(TransportConfig::default());
    let (endpoint, _) = endpoint.bind(&"0.0.0.0:0".parse().unwrap())?;
    endpoint.connect("example.com", "443").await
}
  1. Sending and receiving data:
use quinn::{Connection, NewConnection, RecvStream, SendStream};

async fn send_and_receive(conn: NewConnection) {
    let (mut send_stream, mut recv_stream) = conn.open_bi().await.unwrap();
    send_stream.write_all(b"Hello, world!").await.unwrap();
    send_stream.finish().await.unwrap();
    let mut buf = Vec::new();
    recv_stream.read_to_end(&mut buf).await.unwrap();
    println!("Received: {}", String::from_utf8_lossy(&buf));
}
  1. Implementing a QUIC server:
use quinn::{Endpoint, NewConnection, ServerConfig, TransportConfig};

async fn run_server() -> Result<(), quinn::Error> {
    let mut server_config = ServerConfig::default();
    server_config.transport = TransportConfig::default();
    let (endpoint, _) = Endpoint::builder()
        .listen(server_config)
        .bind(&"0.0.0.0:8080".parse().unwrap())?;
    loop {
        let (conn, _) = endpoint.accept().await?;
        handle_connection(conn).await;
    }
}

async fn handle_connection(conn: NewConnection) {
    // Handle the connection, e.g., by opening streams and sending/receiving data
}

Getting Started

To get started with Quinn, you can follow these steps:

  1. Add the Quinn library to your Cargo.toml file:
[dependencies]
quinn = "0.8.5"
  1. Import the necessary modules and create a new QUIC client:
use quinn::{Endpoint, NewConnection, TransportConfig};

async fn connect() -> Result<NewConnection, quinn::Error> {
    let mut endpoint = Endpoint::builder();

Competitor Comparisons

26,366

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Pros of Tokio

  • Tokio is a mature and widely-used asynchronous runtime, with a large ecosystem of compatible libraries.
  • Tokio provides a comprehensive set of utilities and abstractions for building concurrent and scalable applications.
  • Tokio has excellent documentation and a large community of contributors and users.

Cons of Tokio

  • Tokio's complexity and feature-richness can make it more difficult to learn and understand for beginners.
  • Tokio's focus on providing a wide range of functionality may result in a larger memory footprint and performance overhead compared to more specialized libraries.

Code Comparison

Tokio:

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();

    loop {
        let (mut socket, _) = listener.accept().await.unwrap();
        tokio::spawn(async move {
            let mut buf = [0; 1024];
            loop {
                let n = socket.read(&mut buf).await.unwrap();
                if n == 0 {
                    return;
                }
                socket.write_all(&buf[..n]).await.unwrap();
            }
        });
    }
}

Quinn:

#[tokio::main]
async fn main() {
    let mut listener = quinn::Endpoint::builder()
        .bind("127.0.0.1:8080")
        .await
        .unwrap();

    loop {
        let (connection, _) = listener.accept().await.unwrap();
        tokio::spawn(async move {
            let mut stream = connection.accept_bi().await.unwrap();
            let mut buf = [0; 1024];
            loop {
                let n = stream.read(&mut buf).await.unwrap();
                if n == 0 {
                    return;
                }
                stream.write_all(&buf[..n]).await.unwrap();
            }
        });
    }
}
14,343

An HTTP library for Rust

Pros of Hyper

  • Hyper is a mature and widely-used HTTP library for Rust, with a large and active community.
  • It provides a comprehensive set of features and functionality for building web applications and services.
  • Hyper has excellent documentation and a wealth of community resources available.

Cons of Hyper

  • Hyper may have a higher learning curve compared to Quinn, especially for developers new to Rust.
  • Hyper is primarily focused on HTTP, while Quinn is a more general-purpose networking library.
  • Hyper may have a larger memory footprint and resource requirements compared to Quinn.

Code Comparison

Hyper:

let server = Server::bind(&"127.0.0.1:3000".parse().unwrap())
    .serve(|| {
        service_fn(|req| {
            let response = Response::new(Body::from("Hello, World!"));
            async { Ok::<_, hyper::Error>(response) }
        })
    })
    .await?;

Quinn:

let mut config = quinn::ServerConfig::default();
config.protocols.push(b"http/1.1".to_vec());
let (_, mut incoming) = quinn::Endpoint::server(config, "127.0.0.1:3000".parse().unwrap())?;

while let Some(conn) = incoming.next().await {
    let conn = conn?;
    let mut stream = conn.accept_bi().await?;
    stream.write_all(b"Hello, World!").await?;
}
9,488

A super-easy, composable, web server framework for warp speeds.

Pros of Warp

  • Warp provides a simple and intuitive API for building web applications, making it easy to get started with Rust web development.
  • Warp has a strong focus on performance, with a fast and efficient implementation that can handle high-traffic workloads.
  • Warp's middleware system allows for easy extensibility and customization, making it a flexible choice for a wide range of web applications.

Cons of Warp

  • Warp is primarily focused on building HTTP-based web applications, while Quinn is a more general-purpose networking library that supports a wider range of protocols.
  • Warp's dependency on the Tokio runtime may make it less suitable for certain use cases where a different runtime is preferred.

Code Comparison

Quinn (quinn-rs/quinn):

let mut config = quinn::ServerConfig::default();
config.transport = Arc::new(quinn::TransportConfig {
    max_idle_timeout: Some(Duration::from_secs(30)),
    ..Default::default()
});
let server = quinn::Endpoint::server(config, addr)?;

Warp (seanmonstar/warp):

let routes = warp::path("hello")
    .map(|| "Hello, World!");

let server = warp::serve(routes)
    .run(([127, 0, 0, 1], 3000));
6,269

Metal I/O library for Rust.

Pros of Mio

  • Mio is a low-level, cross-platform I/O library that provides a unified interface for working with various I/O primitives, such as sockets, files, and timers.
  • Mio has a focus on performance and efficiency, making it a suitable choice for building high-performance network applications.
  • Mio is a core component of the Tokio ecosystem, which is a popular asynchronous runtime for Rust.

Cons of Mio

  • Mio is a lower-level library, which means it may require more boilerplate code and a deeper understanding of asynchronous programming to use effectively.
  • Mio does not provide higher-level abstractions or protocols, which may make it less suitable for building complex network applications.

Code Comparison

Mio (Tokio):

let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);

poll.register(&socket, Token(0), Ready::readable(), PollOpt::edge())?;

loop {
    poll.poll(&mut events, None)?;
    for event in events.iter() {
        if event.readiness().is_readable() {
            // Handle readable event
        }
    }
}

Quinn:

let mut quinn = quinn::new(quinn::Config::default());
let mut listener = quinn.listen("0.0.0.0:8080".parse()?)?;

loop {
    let (conn, addr) = listener.accept().await?;
    tokio::spawn(async move {
        // Handle connection
    });
}

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Documentation Crates.io Build status codecov Chat Chat License: MIT License: Apache 2.0

Quinn is a pure-Rust, async-compatible implementation of the IETF QUIC transport protocol. The project was founded by Dirkjan Ochtman and Benjamin Saunders as a side project in 2018, and has seen more than 30 releases since then. If you're using Quinn in a commercial setting, please consider sponsoring the project.

Features

  • Simultaneous client/server operation
  • Ordered and unordered stream reads for improved performance
  • Works on stable Rust, tested on Linux, macOS and Windows
  • Pluggable cryptography, with a standard implementation backed by rustls and ring
  • Application-layer datagrams for small, unreliable messages
  • Future-based async API
  • Minimum supported Rust version of 1.66

Overview

  • quinn: High-level async API based on tokio, see examples for usage. This will be used by most developers. (Basic benchmarks are included.)
  • quinn-proto: Deterministic state machine of the protocol which performs no I/O internally and is suitable for use with custom event loops (and potentially a C or C++ API).
  • quinn-udp: UDP sockets with ECN information tuned for the protocol.
  • bench: Benchmarks without any framework.
  • fuzz: Fuzz tests.

Getting Started

Examples

$ cargo run --example server ./
$ cargo run --example client https://localhost:4433/Cargo.toml

This launches an HTTP 0.9 server on the loopback address serving the current working directory, with the client fetching ./Cargo.toml. By default, the server generates a self-signed certificate and stores it to disk, where the client will automatically find and trust it.

Links

Usage Notes

Click to show the notes

Buffers

A Quinn endpoint corresponds to a single UDP socket, no matter how many connections are in use. Handling high aggregate data rates on a single endpoint can require a larger UDP buffer than is configured by default in most environments. If you observe erratic latency and/or throughput over a stable network link, consider increasing the buffer sizes used. For example, you could adjust the SO_SNDBUF and SO_RCVBUF options of the UDP socket to be used before passing it in to Quinn. Note that some platforms (e.g. Linux) require elevated privileges or modified system configuration for a process to increase its UDP buffer sizes.

Certificates

By default, Quinn clients validate the cryptographic identity of servers they connect to. This prevents an active, on-path attacker from intercepting messages, but requires trusting some certificate authority. For many purposes, this can be accomplished by using certificates from Let's Encrypt for servers, and relying on the default configuration for clients.

For some cases, including peer-to-peer, trust-on-first-use, deliberately insecure applications, or any case where servers are not identified by domain name, this isn't practical. Arbitrary certificate validation logic can be implemented by enabling the dangerous_configuration feature of rustls and constructing a Quinn ClientConfig with an overridden certificate verifier by hand.

When operating your own certificate authority doesn't make sense, rcgen can be used to generate self-signed certificates on demand. To support trust-on-first-use, servers that automatically generate self-signed certificates should write their generated certificate to persistent storage and reuse it on future runs.

Contribution

All feedback welcome. Feel free to file bugs, requests for documentation and any other feedback to the issue tracker.

The quinn-proto test suite uses simulated IO for reproducibility and to avoid long sleeps in certain timing-sensitive tests. If the SSLKEYLOGFILE environment variable is set, the tests will emit UDP packets for inspection using external protocol analyzers like Wireshark, and NSS-compatible key logs for the client side of each connection will be written to the path specified in the variable.

The minimum supported Rust version for published releases of our crates will always be at least 6 months old at the time of release.

NPM DownloadsLast 30 Days