This repository contains all necessary code needed for managed (C#) implementation of the QUIC protocol for .NET.
I have documented some of my development progress on my blog site.
This implementation is currently in the prototype stage. The goal was to obtain a minimal working implementation able to reliably transmit data between client and server. Most unrelated features are left unimplemented.
- Basic connection establishment
- Encryption and TLS implementation backed by modified OpenSSL
- Sending data, flow control, loss recovery, congestion control
- Stream/Connection termination
- Coalescing packets into single UDP datagram
List of highlights of unimplemented protocol features follows
- Connection migration
- 0-RTT data
- Server Preferred Address
Their implementation is subject for future development.
To function correctly, the implementation requires a custom branch of OpenSSL from Akamai https://github.com/akamai/openssl/tree/OpenSSL_1_1_1g-quic. This version of the library is expected to be in the PATH to be loaded by the application.
The need for custom OpenSSL can be avoided by switching to a mock TLS implementation, see Configuration section later.
The mock implementation can be used for trying the library locally, but interoperation with other
QUIC implementations is possible only with the OpenSSL-based TLS. If you want to make sure your
implementation runs with OpenSSL, define the DOTNETQUIC_OPENSSL
environment variable. This will
cause the implementation to throw if OpenSSL cannot be loaded.
Make sure you cloned all git submodules of this repository
git submodule update --init
Follow the guide in Official .NET repository.
The necessary fork of OpenSSL is included as a submodule in extern/openssl
directory. Follow the
readme instructions in OpenSSL's
INSTALL.md
Alternatively, the necessary steps above can be performed via a helper scripts. Make sure all submodules are cloned
git submodule update --init --recursive
Then run the setup script:
# on Linux
./setup.sh
# on Windows
setup.cmd
The scripts will:
- Build the modified
openssl
library using the custom branch of OpenSSL which provides necessary APIs for QUIC The native binaries should be placed inartifacts/openssl
directory in the repository. You then need to add the directory to the path so that the libraries are loaded by .NET at runtime. refer to OpenSSL's INSTALL.md for build prerequisites. - you can also pass
-msquic
option to the script to also build theMsQuic
library which is used in benchmarks to compare the implementation performance. Building msquic requires Powershell Core (even on Linux OS). Refer to msquic README for all prerequisites.
For usage, see examples in the Samples project.
For the list of API methods, see Quic*.cs files inside the repo.
The implementation can produce traces that can be consumed by https://qvis.edm.uhasselt.be
visualizer. To collect traces, define DOTNETQUIC_TRACE
environment variable. The traces will be
saved in the working directory of the program.
The internal implementation of QuicConnection
and related types allows switching the underlying
implementation provider. This can be done either by explicitly passing the provider into the
QuicConnection
and QuicListener
constructors, or overriding the default provider by setting the
DOTNETQUIC_PROVIDER
to one of the following values:
managed
- (default), managed implementation with TLS backed by modified OpenSSL.managedmocktls
- managed implementation with mocked TLS. This works without additional dependencies, but does not interop with other implementations.msquic
- uses theMsQuic
library. Needs msquic.dll to be in path.
The implementation relies on custom-built version of OpenSSL with added API necessary for quic. This therefore requires distributing the modified OpenSSL alongside the implementation.
Currently, only ApplicationProtocols
and Hostname
from SslServerAuthenticationOptions
and
SslClientAuthenticationOptions
are supported. Validation and certificate selection callbacks are
completely unsupported.
Passing X509Certificate
directly requires that the certificate instance contains private key and
is exportable (it needs to be marshalled to OpenSSL library used).
X509Certificate2 cert = new X509Certificate2(cert.pfx, "", X509KeyStorageFlags.Exportable);
Preferred way of specifying the certificate to be used are CertificateFilePath
and
PrivateKeyFilePath
properties on QuicListenerOptions
.