tokio_quicker/
lib.rs

1//! Async QUIC Listener/Socket for [tokio](https://tokio.rs/) using [quiche](https://github.com/cloudflare/quiche).
2//!
3//! ### Examples
4//!
5//! #### [Client](https://github.com/cauvmou/tokio-quic/blob/main/examples/client.rs)
6//!
7//! First create a `QuicSocket`.
8//! ```rust,ignore
9//! let mut connection = QuicSocket::bind("127.0.0.1:0")
10//!         .await?
11//!         .connect(Some("localhost"), "127.0.0.1:4433")
12//!         .await?;
13//! ```
14//! Then you can start opening new `QuicStream`s or receive incoming ones from the server.
15//! ```rust,ignore
16//! let mut stream = connection.bidi(1).await?;
17//! ```
18//! ```rust,ignore
19//! let mut stream = connection.incoming().await?;
20//! ```
21//! These implement the tokio `AsyncRead` and `AsyncWrite` traits.
22//!
23//! #### [Server](https://github.com/cauvmou/tokio-quic/blob/main/examples/server.rs)
24//!
25//! Again create a `QuicListener`.
26//!
27//! ```rust,ignore
28//! let mut listener = QuicListener::bind("127.0.0.1:4433").await?;
29//! ```
30//! Then you can use a while loop to accept incoming connection and either handle them directly on the thread or move them to a new one.
31//! ```rust,ignore
32//! while let Ok(mut connection) = listener.accept().await {
33//!     tokio::spawn(async move {
34//!         let mut stream = connection.incoming().await?;
35//!         ...
36//!         stream.shutdown().await?;
37//!     });
38//! }
39//! ```
40
41use log::trace;
42use std::sync::Arc;
43
44use crate::backend::Handshaker;
45use backend::{
46    client,
47    manager::{self, Manager},
48    server,
49    timer::Timer,
50};
51use config::{MAX_DATAGRAM_SIZE, STREAM_BUFFER_SIZE};
52use connection::{QuicConnection, ToClient, ToServer};
53use error::Result;
54use quiche::ConnectionId;
55use rand::Rng;
56use ring::rand::SystemRandom;
57use tokio::{
58    net::{ToSocketAddrs, UdpSocket},
59    sync::mpsc::{self, UnboundedReceiver},
60    task::JoinHandle,
61};
62
63mod backend;
64pub mod config;
65pub mod connection;
66mod crypto;
67pub mod error;
68pub mod stream;
69
70#[derive(Debug)]
71pub(crate) enum Message {
72    Data {
73        stream_id: u64,
74        bytes: Vec<u8>,
75        fin: bool,
76    },
77    Close(u64),
78}
79
80/// `QuicListener` is used to bind to a specified address/port.
81///
82/// It can be configured using a `quiche::Config` struct.
83/// A base config can be obtained from `tokio_quic::config::default()`.
84///
85/// If the feature `key-gen` is enabled this config will already come with a certificate and private key,
86/// although these are just for testing and are not recommended to be used in production.
87pub struct QuicListener {
88    io: Arc<UdpSocket>,
89    #[allow(unused)]
90    handle: JoinHandle<Result<()>>,
91    connection_recv: UnboundedReceiver<manager::Client>,
92}
93
94impl QuicListener {
95    #[cfg(not(feature = "key-gen"))]
96    pub async fn bind<A: ToSocketAddrs>(
97        addr: A,
98        key_pem: &str,
99        cert_pem: &str,
100        secret: Vec<u8>,
101    ) -> Result<Self> {
102        let mut config = config::default();
103        config.load_priv_key_from_pem_file(key_pem).unwrap();
104        config.load_cert_chain_from_pem_file(cert_pem).unwrap();
105        Self::bind_with_config(addr, config, secret).await
106    }
107
108    #[cfg(feature = "key-gen")]
109    pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<Self> {
110        use ring::rand::Random;
111        let rng = SystemRandom::new();
112        let random: Random<[u8; 16]> = ring::rand::generate(&rng).unwrap();
113        Self::bind_with_config(addr, config::default(), random.expose().to_vec()).await
114    }
115
116    pub async fn bind_with_config<A: ToSocketAddrs>(
117        addr: A,
118        config: quiche::Config,
119        secret: Vec<u8>,
120    ) -> Result<Self> {
121        trace!("Bind listener [{secret:?}]");
122        let io = Arc::new(UdpSocket::bind(addr).await?);
123        let rng = SystemRandom::new();
124        let (tx, connection_recv) = mpsc::unbounded_channel();
125        let manager = Manager::new(
126            io.clone(),
127            ring::hmac::Key::generate(ring::hmac::HMAC_SHA256, &rng).unwrap(),
128            secret,
129            config,
130            tx,
131        );
132        let handle = tokio::spawn(manager);
133        Ok(Self {
134            io,
135            handle,
136            connection_recv,
137        })
138    }
139
140    /// Accepts a incoming connection.
141    pub async fn accept(&mut self) -> Result<QuicConnection<ToClient>> {
142        let manager::Client { connection, recv } = self.connection_recv.recv().await.unwrap();
143
144        let mut inner = server::Inner {
145            io: self.io.clone(),
146            connection,
147            data_recv: recv,
148            send_flush: false,
149            send_end: 0,
150            send_pos: 0,
151            recv_buf: vec![0; STREAM_BUFFER_SIZE],
152            send_buf: vec![0; MAX_DATAGRAM_SIZE],
153            timer: Timer::Unset,
154            last_address: None,
155        };
156        trace!(
157            "Accepted connection trace-id: {:?}, server-name: {:?}",
158            inner.connection.trace_id(),
159            inner.connection.server_name()
160        );
161        Handshaker(&mut inner).await?;
162        trace!(
163            "Handshake complete trace-id: {:?}, server-name: {:?}",
164            inner.connection.trace_id(),
165            inner.connection.server_name()
166        );
167        Ok(QuicConnection::<ToClient>::new(inner))
168    }
169}
170
171/// `QuicSocket` opens a connection from a specified address/port to a server.
172///
173/// It can be configured using a `quiche::Config` struct.
174/// A base config can be obtained from `tokio_quic::config::default()`.
175///
176/// If the feature `key-gen` is enabled this config will already come with a certificate and private key,
177/// although these are just for testing and are not recommended to be used in production.
178pub struct QuicSocket {
179    io: Arc<UdpSocket>,
180    config: quiche::Config,
181}
182
183impl QuicSocket {
184    #[cfg(not(feature = "key-gen"))]
185    /// Bind to a specified address.
186    pub async fn bind<A: ToSocketAddrs>(addr: A, key_pem: &str, cert_pem: &str) -> Result<Self> {
187        let mut config = config::default();
188        config.load_priv_key_from_pem_file(key_pem).unwrap();
189        config.load_cert_chain_from_pem_file(cert_pem).unwrap();
190        Self::bind_with_config(addr, config).await
191    }
192
193    #[cfg(feature = "key-gen")]
194    /// Bind to a specified address.
195    pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<Self> {
196        Self::bind_with_config(addr, config::default()).await
197    }
198
199    /// Bind to a specified address with a `quiche::Config`.
200    pub async fn bind_with_config<A: ToSocketAddrs>(
201        addr: A,
202        config: quiche::Config,
203    ) -> Result<Self> {
204        Ok(Self {
205            io: Arc::new(UdpSocket::bind(addr).await?),
206            config,
207        })
208    }
209
210    /// Connect to a remote server.
211    ///
212    /// `server_name` needs to have a value in order to validate the server's certificate.
213    /// Can be set to `None`, if validation is turned off.
214    pub async fn connect<A: ToSocketAddrs>(
215        &mut self,
216        server_name: Option<&str>,
217        addr: A,
218    ) -> Result<QuicConnection<ToServer>> {
219        self.io.connect(addr).await?;
220        let mut scid = vec![0; 16];
221        rand::thread_rng().fill(&mut *scid);
222        let scid: ConnectionId = scid.into();
223        let connection = quiche::connect(
224            server_name,
225            &scid,
226            self.io.local_addr()?,
227            self.io.peer_addr()?,
228            &mut self.config,
229        )
230        .unwrap();
231
232        let mut inner = client::Inner {
233            io: self.io.clone(),
234            connection,
235            send_flush: false,
236            send_end: 0,
237            send_pos: 0,
238            recv_buf: vec![0; STREAM_BUFFER_SIZE],
239            send_buf: vec![0; MAX_DATAGRAM_SIZE],
240            timer: Timer::Unset,
241        };
242
243        Handshaker(&mut inner).await?;
244
245        Ok(QuicConnection::<ToServer>::new(inner))
246    }
247}