fastnet 0.2.0

Ultra-low latency encrypted networking for real-time games. TLS 1.3 + ChaCha20-Poly1305 with ~15µs RTT.
Documentation
╔═╗╔═╗╔═╗╔╦╗╔╗╔╔═╗╔╦╗
╠╣ ╠═╣╚═╗ ║ ║║║║╣  ║   Ultra-low latency encrypted networking
╚  ╩ ╩╚═╝ ╩ ╝╚╝╚═╝ ╩   for real-time games

Crates.io Documentation License

FastNet is a high-performance networking library designed for real-time multiplayer games. It provides encrypted UDP communication with latencies as low as 15 microseconds while maintaining strong security through TLS 1.3 and ChaCha20-Poly1305 encryption.


Features

  • Ultra-Low Latency: ~12-15µs average RTT on localhost, competitive with raw UDP
  • Built-in Encryption: TLS 1.3 handshake + ChaCha20-Poly1305 AEAD
  • Zero-Alloc Hot Path: Fixed buffers, no allocations in send/recv loop
  • Key Rotation: Automatic key rotation for forward secrecy
  • Linux Tuning: SO_BUSY_POLL, IP_TOS, sendmmsg/recvmmsg batching
  • Zero Configuration Security: No need to understand cryptography
  • Game Engine Ready: C/C++ FFI for Unreal Engine, Unity, Godot
  • Async/Await: Built on Tokio for efficient I/O
  • Reliable & Unreliable Channels: Choose the right mode for your data
  • P2P Networking: Direct peer-to-peer connections with NAT traversal
  • TCP Fallback: Automatic fallback when UDP is blocked
  • Asset Distribution: Large file transfers with LZ4 compression and BLAKE3 verification

Benchmarks

Tested with 50,000 packets at 10,000 packets/second on localhost:

Metric ENet FastNet QUIC
Avg Latency 112.7 µs 15.6 µs 64.0 µs
P99 Latency 143.0 µs 69.6 µs 170.0 µs
Max Latency 323 µs 103.6 µs 1868 µs
Encryption None ChaCha20 TLS
Average Latency (lower is better)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

FastNet      ██ 15.6 µs ⚡
QUIC         ████████ 64.0 µs
ENet         ██████████████ 112.7 µs

7x faster than ENet with full encryption enabled

Note: Max latency spikes in FastNet/QUIC are due to TLS overhead during handshake


Quick Start

Rust

Add to your Cargo.toml:

[dependencies]
fastnet = "0.1"
tokio = { version = "1", features = ["rt-multi-thread"] }

Server:

use fastnet::net::SecureSocket;
use std::net::SocketAddr;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // Load TLS certificates
    let certs = load_certs("cert.pem")?;
    let key = load_key("key.pem")?;
    
    let udp_addr: SocketAddr = "0.0.0.0:7777".parse().unwrap();
    let tcp_addr: SocketAddr = "0.0.0.0:7778".parse().unwrap();
    
    let mut socket = SecureSocket::bind_server(udp_addr, tcp_addr, certs, key).await?;
    println!("Server listening on {}", udp_addr);
    
    loop {
        for event in socket.poll().await? {
            match event {
                SecureEvent::Connected(peer_id) => {
                    println!("Peer {} connected", peer_id);
                }
                SecureEvent::Data(peer_id, channel, data) => {
                    // Echo back
                    socket.send(peer_id, channel, data).await?;
                }
                SecureEvent::Disconnected(peer_id) => {
                    println!("Peer {} disconnected", peer_id);
                }
            }
        }
    }
}

Client:

use fastnet::net::SecureSocket;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let server_addr = "127.0.0.1:7778".parse().unwrap();
    let mut socket = SecureSocket::connect(server_addr).await?;
    
    // Send data on channel 0
    socket.send(1, 0, b"Hello, server!".to_vec()).await?;
    
    // Receive events
    for event in socket.poll().await? {
        if let SecureEvent::Data(_, _, data) = event {
            println!("Received: {:?}", data);
        }
    }
    
    Ok(())
}

C/C++ Integration

Building the Library

Add the crate into your project:

fastnet = { version = "0.1", features = ["ffi"] }

or clone the repo into your machine:

git clone https://github.com/filipe-freitas-dev/fastnet.git

then build the C/C++ wrapper with:

cargo build --release --features ffi

This produces:

  • Linux: target/release/libfastnet.so
  • Windows: target/release/fastnet.dll
  • macOS: target/release/libfastnet.dylib

C Example

#include "fastnet.h"

int main() {
    // Connect to server
    FastNetClient client = fastnet_client_connect("127.0.0.1", 7778);
    if (!client) {
        printf("Failed to connect\n");
        return 1;
    }
    
    // Send data
    uint8_t data[] = {1, 2, 3, 4};
    fastnet_client_send(client, 0, data, sizeof(data));
    
    // Process events
    FastNetEvent event;
    while (fastnet_client_poll(client, &event)) {
        switch (event.type) {
            case FASTNET_EVENT_CONNECTED:
                printf("Connected as peer %d\n", event.peer_id);
                break;
            case FASTNET_EVENT_DATA:
                printf("Received %d bytes\n", event.data_len);
                break;
            case FASTNET_EVENT_DISCONNECTED:
                printf("Disconnected\n");
                break;
        }
    }
    
    fastnet_client_disconnect(client);
    return 0;
}

Unreal Engine Integration

  1. Copy the library to your project:

    YourProject/
    ├── Binaries/
    │   └── Win64/
    │       └── fastnet.dll
    └── Source/
        └── YourGame/
            ├── fastnet.h
            └── FastNet.h (C++ wrapper)
    
  2. Update your Build.cs:

    PublicAdditionalLibraries.Add(
        Path.Combine(ModuleDirectory, "..", "..", "Binaries", "Win64", "fastnet.dll")
    );
    
  3. Use in your code:

    #include "FastNet.h"
    
    // In your GameInstance
    TUniquePtr<FFastNetClient> NetworkClient;
    
    void UMyGameInstance::Init()
    {
        NetworkClient = MakeUnique<FFastNetClient>();
        if (NetworkClient->Connect("127.0.0.1", 7778))
        {
            UE_LOG(LogTemp, Log, TEXT("Connected to server!"));
        }
    }
    
    void UMyGameInstance::Tick(float DeltaTime)
    {
        FFastNetEvent Event;
        while (NetworkClient->Poll(Event))
        {
            switch (Event.Type)
            {
                case EFastNetEventType::Data:
                    ProcessNetworkData(Event.Data);
                    break;
            }
        }
    }
    

P2P Networking

Direct peer-to-peer connections with NAT traversal, eliminating the need for a dedicated relay server.

use fastnet::p2p::{P2PSocket, P2PEvent};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // Connect to signaling server
    let mut socket = P2PSocket::connect("signaling.example.com:9000").await?;
    
    // Join a room to discover peers
    socket.join_room("game-room-123").await?;
    
    loop {
        for event in socket.poll().await? {
            match event {
                P2PEvent::PeerConnected(peer_id) => {
                    println!("Direct connection to peer {}", peer_id);
                    socket.send(peer_id, b"Hello!".to_vec()).await?;
                }
                P2PEvent::Data(peer_id, data) => {
                    println!("From {}: {:?}", peer_id, data);
                }
                P2PEvent::PeerRelayed(peer_id) => {
                    println!("Peer {} using relay (NAT traversal failed)", peer_id);
                }
                _ => {}
            }
        }
    }
}

Features:

  • UDP hole-punching for NAT traversal
  • Automatic relay fallback when direct connection fails
  • Room-based peer discovery
  • End-to-end encryption (ChaCha20-Poly1305)

TCP Fallback

Automatic fallback to TCP when UDP is blocked (corporate firewalls, some mobile networks).

use fastnet::tcp::{HybridSocket, TransportMode};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // Automatically tries UDP, falls back to TCP if blocked
    let mut socket = HybridSocket::connect("game.example.com:7778").await?;
    
    match socket.transport_mode() {
        TransportMode::Udp => println!("Using UDP (optimal)"),
        TransportMode::Tcp => println!("Using TCP (fallback)"),
    }
    
    // API is identical regardless of transport
    socket.send(1, 0, b"Hello!".to_vec()).await?;
    
    Ok(())
}

Asset Distribution

Efficient large file transfers with chunking, compression, and integrity verification.

use fastnet::assets::{AssetServer, AssetClient, AssetEvent};

// Server: Register and serve assets
let mut server = AssetServer::new(Default::default());
server.register("map.pak", "/game/maps/forest.pak").await?;

// Handle requests
if let Some((transfer_id, info)) = server.handle_request(peer_id, "map.pak") {
    // Send chunks
    while let Some(chunk) = server.get_next_chunk(transfer_id)? {
        send_to_peer(peer_id, chunk);
    }
}

// Client: Download assets
let mut client = AssetClient::new();
client.start_download(transfer_id, info, "/local/maps/forest.pak")?;

// Process chunks
client.receive_chunk(chunk)?;

for event in client.poll_events() {
    match event {
        AssetEvent::Progress { received, total, .. } => {
            println!("Download: {:.1}%", (received as f64 / total as f64) * 100.0);
        }
        AssetEvent::Completed { path, .. } => {
            println!("Downloaded: {:?}", path);
        }
        _ => {}
    }
}

Features:

  • 64KB chunked transfers
  • LZ4 compression for faster transfers
  • BLAKE3 hash verification (per-chunk and per-file)
  • Resumable downloads with resume_download()
  • Pause/cancel with pause_transfer(), cancel_transfer()
  • Transfer statistics with get_transfer_stats()
  • Retry tracking for failed chunks

Performance Tuning

FastNet includes OS-level optimizations for minimal jitter:

use fastnet::net::fast::{SocketConfig, batch};

// Apply low-latency configuration
let config = SocketConfig::low_latency();
// - SO_RCVBUF/SO_SNDBUF: 8MB
// - SO_BUSY_POLL: 100µs
// - IP_TOS: 0xB8 (DSCP EF)
// - SO_PRIORITY: 6

// Batch sending (Linux only)
let mut send_batch = batch::SendBatch::new();
send_batch.push(&packet_data, peer_addr);
send_batch.push(&packet_data2, peer_addr2);
batch::sendmmsg(&socket, &send_batch)?;

Linux Tuning Options:

  • SO_RCVBUF/SO_SNDBUF: 4-8MB buffers
  • SO_BUSY_POLL: CPU polling for ~10µs latency reduction
  • IP_TOS: DSCP EF (Expedited Forwarding) for QoS
  • sendmmsg/recvmmsg: Batch multiple packets per syscall

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         Application                              │
├─────────────────────────────────────────────────────────────────┤
│                        SecureSocket                              │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │   TLS 1.3       │  │  ChaCha20       │  │    Channels     │ │
│  │   Handshake     │──│  Poly1305       │──│   (Reliable/    │ │
│  │   (~40ms)       │  │  Encryption     │  │   Unreliable)   │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
│                              │                                   │
│                    ┌─────────┴─────────┐                        │
│                    │   UDP Transport   │                        │
│                    │   (Zero-copy)     │                        │
│                    └───────────────────┘                        │
└─────────────────────────────────────────────────────────────────┘

Security Model

  1. Connection: Client connects via TCP for TLS 1.3 handshake
  2. Key Exchange: Server generates unique ChaCha20 keys per client
  3. Data Transfer: All UDP packets encrypted with AEAD
  4. Authentication: Each packet includes authentication tag

Channels

Channel Use Case Properties
0 - Reliable Ordered Chat, Commands Guaranteed delivery & order
1 - Unreliable Position updates Fast, may drop
2 - Reliable Unordered Item pickups Guaranteed, any order
3 - Sequenced Input, Voice Latest packet only

Generating Certificates

For development:

# Generate self-signed certificate (valid for 365 days)
openssl req -x509 -newkey rsa:4096 \
    -keyout key.pem -out cert.pem \
    -days 365 -nodes \
    -subj "/CN=localhost"

For production, use certificates from Let's Encrypt or your CA.


Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Licensed under either of:

at your option.