networkframework 0.13.3

Safe Rust bindings for Apple's Network.framework — modern, post-CFNetwork TCP / UDP / TLS / Bonjour networking on macOS
Documentation

networkframework-rs

Safe Rust bindings for Apple's Network.framework, backed by a Swift bridge plus an opt-in raw FFI surface.

SDK coverage: 500 / 500 SDK symbols verified, macOS 26.2 SDK. See COVERAGE.md for the logical-area map and COVERAGE_AUDIT.md for the symbol-by-symbol audit.

Why this crate

  • Broad transport coverage: TCP clients and listeners, UDP, TLS, QUIC, WebSocket, and Bonjour discovery/advertising all live in one safe crate.
  • More than sockets: endpoints, connection parameters, path monitoring, content contexts, framers, connection groups, privacy contexts, and resolver / proxy configuration are part of the public safe API.
  • Async where it helps: this is the Tier 1 crate with a native async/await story for Network.framework event streams.
  • Runtime-gated APIs handled for you: newer framework features stay safe, and unsupported runtime combinations surface as Rust errors instead of raw Objective-C / C state leaking upward.
  • Escape hatch available: enable raw-ffi when you need direct bridge access beyond the safe wrappers.

Feature flags

  • Default: safe blocking + callback-oriented API.
  • async: enables networkframework::async_api stream wrappers.
  • raw-ffi: exposes networkframework::raw_ffi::*.

Installation

[dependencies]
networkframework = "0.13.1"

Enable async support explicitly when you want awaitable event streams:

[dependencies]
networkframework = { version = "0.13.1", features = ["async"] }

Async usage

The networkframework::async_api module turns callback-based Network.framework notifications into executor-agnostic Rust futures/streams. It does not lock you into Tokio, async-std, or any other runtime-specific public API. Instead, the crate uses doom-fish-utils async primitives (doom_fish_utils::completion helpers plus the stream-based next().await surface) so the same types compose with whatever executor your application already uses.

Today the async surface includes:

  • ConnectionStateStream
  • ConnectionViabilityStream
  • ConnectionBetterPathStream
  • ConnectionPathChangedStream
  • ListenerEventStream
  • PathUpdateStream
  • BrowserEventStream

A minimal async round trip can use an awaitable listener stream while keeping transport I/O on the same TcpClient / accepted-connection types as the sync API:

use networkframework::async_api::{ListenerEvent, ListenerEventStream};
use networkframework::{TcpClient, TcpListener};

async fn run() -> Result<(), networkframework::NetworkError> {
    let listener = TcpListener::bind(0)?;
    let port = listener.local_port();
    let events = ListenerEventStream::subscribe(&listener, 8);

    let client = TcpClient::connect("127.0.0.1", port)?;
    client.send(b"ping")?;

    while let Some(event) = events.next().await {
        match event {
            ListenerEvent::NewConnection(server) => {
                let request = server.receive(1024)?;
                assert_eq!(request, b"ping");
                server.send(b"pong")?;
                break;
            }
            ListenerEvent::State { .. } => {}
        }
    }

    let reply = client.receive(1024)?;
    assert_eq!(reply, b"pong");
    Ok(())
}

For tiny binaries, pollster::block_on(run()) is often enough. In larger applications, just await the same stream types from your existing runtime. The bundled 07_async_streams example shows PathUpdateStream and ConnectionStateStream in practice.

Sync / callback usage

The original API remains small and direct for request / response flows. If you prefer a blocking round trip, the same TCP primitives work without any feature flags:

use networkframework::{TcpClient, TcpListener};

fn main() -> Result<(), networkframework::NetworkError> {
    let listener = TcpListener::bind(0)?;
    let port = listener.local_port();
    let server = std::thread::spawn(move || -> Result<(), networkframework::NetworkError> {
        let connection = listener.accept()?;
        let request = connection.receive(1024)?;
        assert_eq!(request, b"ping");
        connection.send(b"pong")?;
        Ok(())
    });

    let client = TcpClient::connect("127.0.0.1", port)?;
    client.send(b"ping")?;
    let reply = client.receive(1024)?;
    assert_eq!(reply, b"pong");

    server.join().expect("server thread")?;
    Ok(())
}

Callback-oriented APIs are still available for long-lived observers and framework-managed events. Common entry points include start_path_monitor, start_browser_with_descriptor, start_browser_results_with_descriptor, advertise_with_descriptor, and the various set_*_handler hooks on connection, group, and protocol types.

Examples

The repository ships runnable examples across the main areas of the crate:

  • 01_get_example — local TCP listener/client round trip.
  • 02_tls_getConnectionParameters policy tuning and protocol stacking.
  • 03_udp_and_path — UDP parameters, endpoint construction, and path monitor snapshots.
  • 04_bonjour — Bonjour browse descriptors and browser events.
  • 05_websocket — WebSocket protocol definitions plus QUIC option inspection.
  • 06_bonjour_advertise — Bonjour advertising with TXT records.
  • 07_async_streams — async stream subscriptions for path and connection events (--features async).
  • framer_length_prefix — custom length-prefixed framer wiring.
  • interface_list — enumerating local network interfaces.
  • connection_group — multicast connection groups and state callbacks.
  • content_context_overview — content-context identifiers, priorities, and antecedents.
  • resolver_overview — DNS-over-HTTPS and DNS-over-TLS resolver configs.
  • privacy_context_overview — encrypted name resolution plus proxy policy.
  • quic_options — QUIC transport tuning and ALPN setup.

Run any example directly:

cargo run --example 01_get_example
cargo run --example 07_async_streams --features async

Coverage and audit

  • COVERAGE.md — logical-area coverage map, example links, and test references.
  • COVERAGE_AUDIT.md — full audited SDK symbol table for the macOS 26.2 headers.

Availability notes

Some Apple APIs are runtime-gated by the operating system:

  • Application-service browsing / advertising / parameters: macOS 13+
  • Relay and Oblivious HTTP proxy configuration: macOS 14+
  • Ultra-constrained path / parameter flags and link quality: newer SDK/runtime combinations

The safe wrappers return NetworkError::InvalidArgument when a requested API is unavailable at runtime.

Validation

cargo build --all-features
cargo clippy --all-targets --all-features -- -D warnings

Status

Actively developed. Targets macOS and tracks the audited Network.framework SDK surface closely.

License

Licensed under either of:

at your option.