vncrs 0.1.8

A pure Rust VNC server library for Windows
docs.rs failed to build vncrs-0.1.8
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: vncrs-0.1.6

Why vncrs

Traditional VNC servers on Windows (like TigerVNC, TightVNC, or UltraVNC) rely on heavy C++ installers, legacy GDI display hooks, or continuous full-frame CPU diffing that hogs 15–25% of your processor.

vncrs solves this with a modern, pure Rust architecture:

  • 0ms CPU dirty detection by reading hardware damage hints directly from the Windows Desktop Window Manager (DWM) compositor.
  • Zero-copy frame swapping using a buffer ping-pong pool that eliminates gigabytes of memory copies per second.
  • Multi-core Rayon fallback with 128-bit SIMD chunk diffing when hardware hints are unavailable.
  • Instant embeddability into any Rust application with a single cargo add vncrs.

Features

  • Zero-Copy Capture Pipeline — Windows Graphics Capture (WGC) frames are swapped via pointer exchange, recycling allocations with zero heap churn and no redundant zeroing memsets.
  • TigerVNC Continuous Updates Push Engine — Full support for RFB pseudo-encoding -313 and Fence -312. Streams frames continuously at display refresh rate without waiting for client RTT pull requests.
  • Tight Encoding with SIMD JPEG & Palette — Prioritizes RFB Tight (ID 7) with instant solid fill (0x80), SIMD-accelerated JPEG (0x90) for video/gradients, and palette deflate for UI/text.
  • Hardware-Driven Dirty Rects — Consumes native compositor damage regions, cutting dirty scanning CPU usage to nearly 0%.
  • SIMD 32-Byte Diffing & Fast Sampling — 32-byte chunk vector diffing and 5-point tile fast rejection when hardware compositor hints are absent.
  • Native ZRLE & SIMD Zlib Compression — Hardware-accelerated zlib-rs deflate engine with 128-bit solid tile fast path, achieving up to 95% bandwidth reduction.
  • Rect Coalescing — Merges adjacent and overlapping damage tiles to minimize protocol packet overhead and zlib stream flushes.
  • Full Input Injection — Mouse movement, 4-way scrolling, control keys, and full Cyrillic/Unicode keyboard mapping via enigo.
  • Hardened Against DoS — Bounded message parsers (prevents OOM exploits), constant-time challenge auth, and no misaligned pointer casts.

When to Use

  • Use vncrs when: You need high-FPS, low-latency remote desktop streaming on Windows without installing heavy third-party services, or want to embed remote desktop sharing inside your own Rust app or bot.
  • Not for: Linux/macOS display servers (this crate leverages Windows Graphics Capture and Windows input synthesis APIs).

Quick Start

1. Add dependency

cargo add vncrs

2. Run minimal server

use vncrs::{VncServer, VncServerConfig};
use vncrs::capture::windows::WindowsCapture;
use vncrs::input::enigo_input::EnigoInput;

fn main() -> vncrs::Result<()> {
    let config = VncServerConfig::new()
        .port(5900)
        .password("secret")
        .name("My Workstation")
        .max_fps(60);

    let capture = WindowsCapture::new()?;
    let input = EnigoInput::new();

    let mut server = VncServer::new(capture, input, config);
    server.listen()
}

3. Connect

Connect with any standard VNC viewer:

vncviewer 127.0.0.1:5900

Examples

Three ready-to-run examples are included:

Simple Server

Minimal server listening on port 5900:

cargo run --example simple_server

Headless / View-Only Server

Shares your screen with remote input strictly disabled:

cargo run --example headless

Full CLI Server

Feature-complete command-line server with CLI flags:

cargo run --example full_server -- --port 5900 --password secret --fps 60 --name "Workstation"
Flag Default Description
-p, --port <PORT> 5900 TCP listen port
--password <PASS> None Access password (max 8 characters per RFB standard)
-n, --name <NAME> "Rust VNC" Display name broadcasted to connecting viewers
--fps <FPS> 60 Max frame rate (1–240 FPS)
--view-only false Disallow remote keyboard and mouse input
-v, --verbose false Enable structured log output

Performance

Encoding Efficiency Matrix

Encoding RFB ID Best For Compression Ratio CPU Overhead
Tight 7 Standard high-FPS streaming, video & 3D (TigerVNC, Remmina, noVNC) Exceptional (~90-98% reduction) Ultra-Low (Instant solid fill & SIMD JPEG)
ZRLE 16 UI/Desktop text with lossless requirements Highest lossless (~95% reduction) Ultra-Low (128-bit solid tile fast path)
Hextile 5 Low-latency local networks Moderate (~60% reduction) Minimal
Zlib 6 Streaming over constrained connections High (~80% reduction) Moderate
Raw 0 Loopback / ultra-high bandwidth 0% (raw BGRA stream) Zero

Architectural Highlights

  • Hardware Compositor Dirty Hints: Unlike legacy servers that compute pixel-by-pixel diffs on the CPU, vncrs reads dirty regions reported by the Windows compositor D3D11 surface.
  • Zero-Copy Ring Pool: Framebuffers are swapped via std::mem::swap between the capture worker thread and the server session loop, preventing megabytes of memcpy per frame.
  • Rect Coalescing Engine: Blends fragmented damage tiles into optimized bounding boxes, drastically cutting down TCP packet headers and zlib stream resets.

Configuration

VncServerConfig uses a type-safe builder pattern:

let config = vncrs::VncServerConfig::new()
    .port(5900)
    .password("pass1234")
    .name("Gaming Rig")
    .max_fps(144)      // Clamped to [1, 240]
    .tile_size(64);    // Clamped to [16, 256]

Graceful Programmatic Shutdown

use std::sync::atomic::Ordering;

let server = vncrs::VncServer::new(capture, input, config);
let running = server.running_flag();

ctrlc::set_handler(move || {
    running.store(false, Ordering::Relaxed);
}).ok();

server.listen()?;

Extensibility

Custom ScreenCapture

Feed frames from DirectX games, virtual monitors, or custom pipelines:

pub trait ScreenCapture {
    fn width(&self) -> u16;
    fn height(&self) -> u16;
    fn stride(&self) -> usize;

    /// Swap buffer with zero allocations. Returns Ok(true) if a fresh frame is ready.
    fn swap_frame(&mut self, buf: &mut Vec<u8>) -> vncrs::Result<bool>;

    /// Optional hardware dirty rect hints from compositor
    fn take_dirty_hints(&mut self, _out: &mut Vec<CaptureRect>) -> bool { false }
}

Custom InputHandler

Direct remote control events to an isolated sandbox or game automation framework:

pub trait InputHandler {
    fn move_mouse(&mut self, x: u16, y: u16);
    fn mouse_button(&mut self, button: u8, pressed: bool);
    fn scroll(&mut self, direction: ScrollDirection);
    fn key_event(&mut self, keysym: u32, down: bool);
}

Security

  1. Network Boundary: Standard VNC (RFB 3.8) challenge-response authentication uses 56-bit DES without transport layer encryption. For untrusted public networks, route through an SSH tunnel or WireGuard / Tailscale VPN:
    ssh -L 5900:127.0.0.1:5900 user@remote-windows-host
    
  2. View-Only Mode: Pass vncrs::input::NoopInput when only observation is needed to lock out any remote input injection.
  3. Memory Safety: Every packet parser enforces strict bounds (e.g. 1 MB limit on clipboard text) to neutralize remote buffer allocation attacks.

License

Distributed under the MIT License.