1![quiche](quiche.svg) 2 3[![crates.io](https://img.shields.io/crates/v/quiche.svg)](https://crates.io/crates/quiche) 4[![docs.rs](https://docs.rs/quiche/badge.svg)](https://docs.rs/quiche) 5[![license](https://img.shields.io/github/license/cloudflare/quiche.svg)](https://opensource.org/licenses/BSD-2-Clause) 6![build](https://img.shields.io/github/actions/workflow/status/cloudflare/quiche/stable.yml?branch=master) 7 8[quiche] is an implementation of the QUIC transport protocol and HTTP/3 as 9specified by the [IETF]. It provides a low level API for processing QUIC packets 10and handling connection state. The application is responsible for providing I/O 11(e.g. sockets handling) as well as an event loop with support for timers. 12 13For more information on how quiche came about and some insights into its design 14you can read a [post] on Cloudflare's blog that goes into some more detail. 15 16[quiche]: https://docs.quic.tech/quiche/ 17[ietf]: https://quicwg.org/ 18[post]: https://blog.cloudflare.com/enjoy-a-slice-of-quic-and-rust/ 19 20Who uses quiche? 21---------------- 22 23### Cloudflare 24 25quiche powers Cloudflare edge network's [HTTP/3 support][cloudflare-http3]. The 26[cloudflare-quic.com](https://cloudflare-quic.com) website can be used for 27testing and experimentation. 28 29### Android 30 31Android's DNS resolver uses quiche to [implement DNS over HTTP/3][android-http3]. 32 33### curl 34 35quiche can be [integrated into curl][curl-http3] to provide support for HTTP/3. 36 37### NGINX (unofficial) 38 39quiche can be [integrated into NGINX](nginx/) using an unofficial patch to 40provide support for HTTP/3. 41 42[cloudflare-http3]: https://blog.cloudflare.com/http3-the-past-present-and-future/ 43[android-http3]: https://security.googleblog.com/2022/07/dns-over-http3-in-android.html 44[curl-http3]: https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version 45 46Getting Started 47--------------- 48 49### Command-line apps 50 51Before diving into the quiche API, here are a few examples on how to use the 52quiche tools provided as part of the [quiche-apps](apps/) crate. 53 54After cloning the project according to the command mentioned in the [building](#building) section, the client can be run as follows: 55 56```bash 57 $ cargo run --bin quiche-client -- https://cloudflare-quic.com/ 58``` 59 60while the server can be run as follows: 61 62```bash 63 $ cargo run --bin quiche-server -- --cert apps/src/bin/cert.crt --key apps/src/bin/cert.key 64``` 65 66(note that the certificate provided is self-signed and should not be used in 67production) 68 69Use the `--help` command-line flag to get a more detailed description of each 70tool's options. 71 72### Configuring connections 73 74The first step in establishing a QUIC connection using quiche is creating a 75[`Config`] object: 76 77```rust 78let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; 79config.set_application_protos(&[b"example-proto"]); 80 81// Additional configuration specific to application and use case... 82``` 83 84The [`Config`] object controls important aspects of the QUIC connection such 85as QUIC version, ALPN IDs, flow control, congestion control, idle timeout 86and other properties or features. 87 88QUIC is a general-purpose transport protocol and there are several 89configuration properties where there is no reasonable default value. For 90example, the permitted number of concurrent streams of any particular type 91is dependent on the application running over QUIC, and other use-case 92specific concerns. 93 94quiche defaults several properties to zero, applications most likely need 95to set these to something else to satisfy their needs using the following: 96 97- [`set_initial_max_streams_bidi()`] 98- [`set_initial_max_streams_uni()`] 99- [`set_initial_max_data()`] 100- [`set_initial_max_stream_data_bidi_local()`] 101- [`set_initial_max_stream_data_bidi_remote()`] 102- [`set_initial_max_stream_data_uni()`] 103 104[`Config`] also holds TLS configuration. This can be changed by mutators on 105the an existing object, or by constructing a TLS context manually and 106creating a configuration using [`with_boring_ssl_ctx()`]. 107 108A configuration object can be shared among multiple connections. 109 110### Connection setup 111 112On the client-side the [`connect()`] utility function can be used to create 113a new connection, while [`accept()`] is for servers: 114 115```rust 116// Client connection. 117let conn = quiche::connect(Some(&server_name), &scid, local, peer, &mut config)?; 118 119// Server connection. 120let conn = quiche::accept(&scid, None, local, peer, &mut config)?; 121``` 122 123### Handling incoming packets 124 125Using the connection's [`recv()`] method the application can process 126incoming packets that belong to that connection from the network: 127 128```rust 129let to = socket.local_addr().unwrap(); 130 131loop { 132 let (read, from) = socket.recv_from(&mut buf).unwrap(); 133 134 let recv_info = quiche::RecvInfo { from, to }; 135 136 let read = match conn.recv(&mut buf[..read], recv_info) { 137 Ok(v) => v, 138 139 Err(e) => { 140 // An error occurred, handle it. 141 break; 142 }, 143 }; 144} 145``` 146 147### Generating outgoing packets 148 149Outgoing packet are generated using the connection's [`send()`] method 150instead: 151 152```rust 153loop { 154 let (write, send_info) = match conn.send(&mut out) { 155 Ok(v) => v, 156 157 Err(quiche::Error::Done) => { 158 // Done writing. 159 break; 160 }, 161 162 Err(e) => { 163 // An error occurred, handle it. 164 break; 165 }, 166 }; 167 168 socket.send_to(&out[..write], &send_info.to).unwrap(); 169} 170``` 171 172When packets are sent, the application is responsible for maintaining a 173timer to react to time-based connection events. The timer expiration can be 174obtained using the connection's [`timeout()`] method. 175 176```rust 177let timeout = conn.timeout(); 178``` 179 180The application is responsible for providing a timer implementation, which 181can be specific to the operating system or networking framework used. When 182a timer expires, the connection's [`on_timeout()`] method should be called, 183after which additional packets might need to be sent on the network: 184 185```rust 186// Timeout expired, handle it. 187conn.on_timeout(); 188 189// Send more packets as needed after timeout. 190loop { 191 let (write, send_info) = match conn.send(&mut out) { 192 Ok(v) => v, 193 194 Err(quiche::Error::Done) => { 195 // Done writing. 196 break; 197 }, 198 199 Err(e) => { 200 // An error occurred, handle it. 201 break; 202 }, 203 }; 204 205 socket.send_to(&out[..write], &send_info.to).unwrap(); 206} 207``` 208 209#### Pacing 210 211It is recommended that applications [pace] sending of outgoing packets to 212avoid creating packet bursts that could cause short-term congestion and 213losses in the network. 214 215quiche exposes pacing hints for outgoing packets through the [`at`] field 216of the [`SendInfo`] structure that is returned by the [`send()`] method. 217This field represents the time when a specific packet should be sent into 218the network. 219 220Applications can use these hints by artificially delaying the sending of 221packets through platform-specific mechanisms (such as the [`SO_TXTIME`] 222socket option on Linux), or custom methods (for example by using user-space 223timers). 224 225[pace]: https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 226[`SO_TXTIME`]: https://man7.org/linux/man-pages/man8/tc-etf.8.html 227 228### Sending and receiving stream data 229 230After some back and forth, the connection will complete its handshake and 231will be ready for sending or receiving application data. 232 233Data can be sent on a stream by using the [`stream_send()`] method: 234 235```rust 236if conn.is_established() { 237 // Handshake completed, send some data on stream 0. 238 conn.stream_send(0, b"hello", true)?; 239} 240``` 241 242The application can check whether there are any readable streams by using 243the connection's [`readable()`] method, which returns an iterator over all 244the streams that have outstanding data to read. 245 246The [`stream_recv()`] method can then be used to retrieve the application 247data from the readable stream: 248 249```rust 250if conn.is_established() { 251 // Iterate over readable streams. 252 for stream_id in conn.readable() { 253 // Stream is readable, read until there's no more data. 254 while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) { 255 println!("Got {} bytes on stream {}", read, stream_id); 256 } 257 } 258} 259``` 260 261### HTTP/3 262 263The quiche [HTTP/3 module] provides a high level API for sending and 264receiving HTTP requests and responses on top of the QUIC transport protocol. 265 266[`Config`]: https://docs.quic.tech/quiche/struct.Config.html 267[`set_initial_max_streams_bidi()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_streams_bidi 268[`set_initial_max_streams_uni()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_streams_uni 269[`set_initial_max_data()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_data 270[`set_initial_max_stream_data_bidi_local()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_local 271[`set_initial_max_stream_data_bidi_remote()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_remote 272[`set_initial_max_stream_data_uni()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_uni 273[`with_boring_ssl_ctx()`]: https://docs.quic.tech/quiche/struct.Config.html#method.with_boring_ssl_ctx 274[`connect()`]: https://docs.quic.tech/quiche/fn.connect.html 275[`accept()`]: https://docs.quic.tech/quiche/fn.accept.html 276[`recv()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.recv 277[`send()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.send 278[`timeout()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.timeout 279[`on_timeout()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.on_timeout 280[`stream_send()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.stream_send 281[`readable()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.readable 282[`stream_recv()`]: https://docs.quic.tech/quiche/struct.Connection.html#method.stream_recv 283[HTTP/3 module]: https://docs.quic.tech/quiche/h3/index.html 284 285Have a look at the [quiche/examples/] directory for more complete examples on 286how to use the quiche API, including examples on how to use quiche in C/C++ 287applications (see below for more information). 288 289[examples/]: quiche/examples/ 290 291Calling quiche from C/C++ 292------------------------- 293 294quiche exposes a [thin C API] on top of the Rust API that can be used to more 295easily integrate quiche into C/C++ applications (as well as in other languages 296that allow calling C APIs via some form of FFI). The C API follows the same 297design of the Rust one, modulo the constraints imposed by the C language itself. 298 299When running ``cargo build``, a static library called ``libquiche.a`` will be 300built automatically alongside the Rust one. This is fully stand-alone and can 301be linked directly into C/C++ applications. 302 303Note that in order to enable the FFI API, the ``ffi`` feature must be enabled (it 304is disabled by default), by passing ``--features ffi`` to ``cargo``. 305 306[thin C API]: https://github.com/cloudflare/quiche/blob/master/quiche/include/quiche.h 307 308Building 309-------- 310 311quiche requires Rust 1.66 or later to build. The latest stable Rust release can 312be installed using [rustup](https://rustup.rs/). 313 314Once the Rust build environment is setup, the quiche source code can be fetched 315using git: 316 317```bash 318 $ git clone --recursive https://github.com/cloudflare/quiche 319``` 320 321and then built using cargo: 322 323```bash 324 $ cargo build --examples 325``` 326 327cargo can also be used to run the testsuite: 328 329```bash 330 $ cargo test 331``` 332 333Note that [BoringSSL], which is used to implement QUIC's cryptographic handshake 334based on TLS, needs to be built and linked to quiche. This is done automatically 335when building quiche using cargo, but requires the `cmake` command to be 336available during the build process. On Windows you also need 337[NASM](https://www.nasm.us/). The [official BoringSSL 338documentation](https://github.com/google/boringssl/blob/master/BUILDING.md) has 339more details. 340 341In alternative you can use your own custom build of BoringSSL by configuring 342the BoringSSL directory with the ``QUICHE_BSSL_PATH`` environment variable: 343 344```bash 345 $ QUICHE_BSSL_PATH="/path/to/boringssl" cargo build --examples 346``` 347 348[BoringSSL]: https://boringssl.googlesource.com/boringssl/ 349 350### Building for Android 351 352Building quiche for Android (NDK version 19 or higher, 21 recommended), can be 353done using [cargo-ndk] (v2.0 or later). 354 355First the [Android NDK] needs to be installed, either using Android Studio or 356directly, and the `ANDROID_NDK_HOME` environment variable needs to be set to the 357NDK installation path, e.g.: 358 359```bash 360 $ export ANDROID_NDK_HOME=/usr/local/share/android-ndk 361``` 362 363Then the Rust toolchain for the Android architectures needed can be installed as 364follows: 365 366```bash 367 $ rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android 368``` 369 370Note that the minimum API level is 21 for all target architectures. 371 372[cargo-ndk] (v2.0 or later) also needs to be installed: 373 374```bash 375 $ cargo install cargo-ndk 376``` 377 378Finally the quiche library can be built using the following procedure. Note that 379the `-t <architecture>` and `-p <NDK version>` options are mandatory. 380 381```bash 382 $ cargo ndk -t arm64-v8a -p 21 -- build --features ffi 383``` 384 385See [build_android_ndk19.sh] for more information. 386 387[Android NDK]: https://developer.android.com/ndk 388[cargo-ndk]: https://docs.rs/crate/cargo-ndk 389[build_android_ndk19.sh]: https://github.com/cloudflare/quiche/blob/master/tools/android/build_android_ndk19.sh 390 391### Building for iOS 392 393To build quiche for iOS, you need the following: 394 395- Install Xcode command-line tools. You can install them with Xcode or with the 396 following command: 397 398```bash 399 $ xcode-select --install 400``` 401 402- Install the Rust toolchain for iOS architectures: 403 404```bash 405 $ rustup target add aarch64-apple-ios x86_64-apple-ios 406``` 407 408- Install `cargo-lipo`: 409 410```bash 411 $ cargo install cargo-lipo 412``` 413 414To build libquiche, run the following command: 415 416```bash 417 $ cargo lipo --features ffi 418``` 419 420or 421 422```bash 423 $ cargo lipo --features ffi --release 424``` 425 426iOS build is tested in Xcode 10.1 and Xcode 11.2. 427 428### Building Docker images 429 430In order to build the Docker images, simply run the following command: 431 432```bash 433 $ make docker-build 434``` 435 436You can find the quiche Docker images on the following Docker Hub repositories: 437 438- [cloudflare/quiche](https://hub.docker.com/repository/docker/cloudflare/quiche) 439- [cloudflare/quiche-qns](https://hub.docker.com/repository/docker/cloudflare/quiche-qns) 440 441The `latest` tag will be updated whenever quiche master branch updates. 442 443**cloudflare/quiche** 444 445Provides a server and client installed in /usr/local/bin. 446 447**cloudflare/quiche-qns** 448 449Provides the script to test quiche within the [quic-interop-runner](https://github.com/marten-seemann/quic-interop-runner). 450 451Copyright 452--------- 453 454Copyright (C) 2018-2019, Cloudflare, Inc. 455 456See [COPYING] for the license. 457 458[COPYING]: https://github.com/cloudflare/quiche/tree/master/COPYING 459