Architecture

Understanding the RustVNC library ecosystem.

Library Structure

┌─────────────────────────────────────────────┐
│         Your Application                     │
│    (VNC server, client, proxy, recorder)    │
└─────────────────┬───────────────────────────┘
                  │ uses
┌─────────────────▼───────────────────────────┐
│         rustvncserver                        │
│    ├─ Protocol handling (RFC 6143)          │
│    ├─ Client connection management          │
│    ├─ Authentication                        │
│    └─ Async I/O (Tokio)                     │
└─────────────────┬───────────────────────────┘
                  │ uses
┌─────────────────▼───────────────────────────┐
│         rfb-encodings                        │
│    ├─ 10 encoding implementations           │
│    ├─ Compression stream management         │
│    └─ Pixel format translation              │
└─────────────────────────────────────────────┘

Design Principles

Memory Safety

All libraries are written in safe Rust. No unsafe blocks in core logic. This eliminates:

  • Buffer overflows
  • Use-after-free bugs
  • Data races
  • Null pointer dereferences

Zero-Copy Architecture

Framebuffer data is shared using Arc<[u8]>:

// Single allocation shared by all clients
let framebuffer = Arc::new(pixel_data);

// Clients read directly, no copying
for client in clients {
    client.send_update(Arc::clone(&framebuffer));
}

Persistent Compression Streams

Zlib compressors maintain state across frames for better compression:

// Tight encoding uses 4 persistent streams
struct TightStreamState {
    basic_zlib: ZlibEncoder,   // Stream 0
    fill_zlib: ZlibEncoder,    // Stream 1
    jpeg_zlib: ZlibEncoder,    // Stream 2
    filter_zlib: ZlibEncoder,  // Stream 3
}

Async I/O

Built on Tokio for efficient concurrent connections:

// Handles hundreds of clients efficiently
// No thread-per-client overhead
async fn handle_client(socket: TcpStream, server: Arc<VncServer>) {
    // Non-blocking I/O
    loop {
        let message = read_message(&socket).await?;
        process(message).await;
    }
}

Using rfb-encodings Standalone

The encoding library can be used independently:

use rfb_encodings::{TightEncoder, ZrleEncoder, PixelFormat};

// For a VNC client decoder
let decoder = ZrleDecoder::new();
let pixels = decoder.decode(&wire_data, width, height, &format)?;

// For a VNC proxy/recorder
let encoder = TightEncoder::new();
let wire_data = encoder.encode(&pixels, width, height, &format)?;

Thread Safety

All public types implement Send and Sync:

// Safe to share across threads
let server = Arc::new(VncServer::new(1920, 1080));

// Spawn from multiple threads
let server_clone = Arc::clone(&server);
std::thread::spawn(move || {
    server_clone.update_framebuffer(&pixels, 0, 0, w, h);
});