Matthias Einwag 3a30aa17c8 Prevent sending of ACK-only packets
The priority-based send state implementation had an issue where if returned
`self.can_send() == true` even if no data was available for sending.
This condition lead the `poll_transmit` method to initiate a transmission which
passed the ACK-only check since it assumed there was stream data to send.
However when trying to write stream frames no actual stream data could be
written.

The reason for this was that the `can_send()` condition only checked for the
length of the binary heap. However the length of this one was only reduced
in `write_stream_frames()` when the level was inspected the next time, and
not after data of one level was actually written.

This change fixes that, and drops the unused levels immediately after data
was written. There is on exception however: If only one level is left, it is
kept around and reused for future transmits to avoid deallocating and
reallocating the transmit queue continuously. However the `can_send` check
was updated to account for the empty level.

I also added some additional debug asserts which cross-checks
if an operation which announced to write more than just ACKs
still ended up only writing ACKs. That should make it easier to
determine similar issues in the future.

**Ack only transmissions in benchmark before change:** 1462

**Ack only transmissions in benchmark after change:** 45
2021-06-22 21:16:36 +02:00
2021-05-08 20:26:23 +02:00
2021-06-21 19:21:34 -07:00
2021-06-21 19:21:34 -07:00
2019-10-10 10:12:34 +02:00
2020-01-27 10:21:10 -08:00
2018-04-28 22:07:13 -07:00

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

Pure-rust QUIC protocol implementation

Quinn is a pure-rust, future-based implementation of the QUIC transport protocol undergoing standardization by the IETF. This library is at draft 32.

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
  • Experimental HTTP over QUIC
  • The minimum supported Rust version is 1.47.0

Overview

  • quinn: High-level async API based on tokio, see 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-h3: Contains an implementation of HTTP-3 and QPACK. It is split internally in a deterministic state machine and a tokio-based high-level async API.
  • bench: Benchmarks without any framework.
  • interop: Tooling that helps to run interoperability tests.
  • 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.

Authors

  • Dirkjan Ochtman - Project owner & founder
  • Benjamin Saunders - Project owner & founder
  • Jean-Christophe Begue - Project collaborator, author of the HTTP/3 Implementation
S
Description
noq, a QUIC implementation in Rust
Readme 107 MiB
Languages
Rust 99.3%
Python 0.5%
Shell 0.2%