Crates.io | aeronet_proto |
lib.rs | aeronet_proto |
version | 0.7.0 |
source | src |
created_at | 2024-07-30 08:04:20.617716 |
updated_at | 2024-08-25 08:57:31.370959 |
description | Sans-IO protocol implementation for aeronet |
homepage | |
repository | https://github.com/aecsocket/aeronet |
max_upload_size | |
id | 1319548 |
size | 157,634 |
aeronet_proto
Provides implementations of protocol-level features for aeronet transports.
Since not all underlying transports will offer the same guarantees of what features they provide, this crate offers its own implementation of certain features which are agnostic to the underlying protocol, sans-I/O.
Feature | Description | aeronet_proto |
---|---|---|
buffering | combines small messages into one big packet (like Nagle) | ✅ |
fragmentation | large messages are sent using multiple packets | ✅ |
lane management | messages can be sent over different lanes with different guarantees | ✅ |
reliability | messages sent reliably are guaranteed to be received by the peer | ✅ |
ordering | messages will be received in the same order they were sent | ✅ |
framing | message boundary is maintained by API (i.e. not just stream of bytes) | - |
encryption | unauthorized third parties can't read the network data in transit | - |
authentication | only clients who have permission to use this app can connect | - |
validation | the message was not tampered with or corrupted in transit | - |
congestion control | controls how fast data is sent, in order to not flood the network | - |
negotiation | makes sure that both peers are using the same protocol before talking | - |
The client always acts as the initiator, sending the first message.
Features which are not marked as provided by this crate must be implemented at the transport
implementation level. For example, WebTransport encrypts connections by default, so there is no
point in implementing encryption at the aeronet_proto
level.
If a transport already supports a feature which is provided by the protocol, it is recommended to
use the protocol's implementation instead, as it makes the API more consistent across transport
implementations. For example, QUIC/WebTransport provides reliability and ordering through its
stream mechanism, however these do not support the exact same feature set as aeronet_proto
, so
are not used.
Feature flag: visualizer
The visualizer is a debugging tool built into the crate, which displays plots of network statistics
over time using egui
and egui_plot
. It is compatible with any client transport which uses a
Session
(see SessionBacked
), and may be used in Bevy as well.
See SessionStatsVisualizer
for a description of how to use the visualizer.
The protocol is heavily inspired by Building a Game Network Protocol, with some adjustments in terminology and implementation.
aeronet
] through its -Transport
traits.Session
- can be used to send data over a connection while using the features
outlined in Features i.e. fragmentation, reliability, orderingThe aeronet protocol can be used on top of nearly any transport. The requirements are:
See [ty
] for a full description of the encoded packet layout.
The entry point to the API is the Session
, which manages incoming and outgoing messages without
performing any I/O itself. One can be created using Session::client
or Session::server
and
providing a configuration which determines parameters such as maximum packet length, lanes for
sending/receiving, and how many bytes can be sent out per second.
The API exposes these main functions:
Session::send
to buffer up a message for sending laterSession::flush
to build up the packets which should be sent nowSession::recv
to accept an incoming packet and read its dataSession::update
to update the internal state of the session, and testing if we are using too
much memory (see Memory management)If we do not bound the maximum amount of memory that a session uses, a malicious peer may cause
a denial-of-service by exhausting all of our memory. Therefore, we define a maximum amount of memory
that the session can use, and Session::update
will terminate the connection if we are using too
much.
A session may use too much memory if:
The maximum transmissible unit, or MTU, defines how large a single packet may be, in bytes. If the packet is longer than the MTU, then routers along the network path may drop the packet. To avoid this, the session will never produce a packet which is larger than the user-specified MTU. Messages which are larger than the MTU are split up into smaller fragments and reassembled on the receiving side (with some extra overhead for packet and fragment headers).
When creating the session, you define a minimum MTU and an initial MTU. Fragments will never be
larger than min_mtu - OVERHEAD
, however a packet will never be larger than mtu
(it is not
possible to change how large fragments are during the connection due to how the receiver logic
works).
However, the MTU may change over the lifetime of a connection, and we may be able to take advantage
of a higher path MTU when it is available, and reduce the MTU when it is no longer viable. To
account for this, the session allows you to change the MTU via Session::set_mtu
. The MTU may
never be lower than min_mtu
.
To ensure that protocol code works correctly in all situations, we make use of both unit testing and
fuzz tests. Fuzz tests must be run on Rust nightly (add +nightly
to the command line).
To start a fuzz test, run this from the aeronet_proto/fuzz
directory:
cargo fuzz run <fuzz_target>