macula_quic (macula v8.7.0)

View Source

Macula QUIC transport — Quinn-based Rust NIF.

Provides QUIC listener, connection, and stream operations backed by Quinn (Rust). Listeners bind to specific IP addresses, enabling per-identity IPv6 binding for virtual relay identities.

Active-mode messages delivered to owning process: {quic, Data, StreamRef, Flags} — stream data {quic, new_conn, ConnRef, Info} — new connection accepted {quic, new_stream, StreamRef, Props} — new stream accepted {quic, peer_send_shutdown, StreamRef, undefined} {quic, stream_closed, StreamRef, Flags} {quic, shutdown, Handle, Reason}

Summary

Functions

Accept stream with options and timeout (for macula_dist).

Start accepting connections on a listener. Delivers {quic, new_conn, ConnRef, Info} to the calling process.

Start accepting streams on a connection. Delivers {quic, new_stream, StreamRef, #{conn => ConnRef}} to the owning process.

Send data asynchronously.

Async shutdown connection.

Generic close — tries stream, then connection, then listener.

Close a connection.

Close a listener.

Close a stream.

Connect to a remote QUIC server. Host is a hostname or IP-string; validation depends on verify / verify_pubkey opts.

Transfer ownership of a handle to another process. Works with both stream and connection handles.

Generate a self-signed X.509 cert from an Ed25519 keypair. Returns {ok, {CertPem, KeyPem}} as PEM-encoded binaries suitable for handing to macula_quic:listen/3 via cert / key opts (after writing to disk). The cert wraps the identity's macula pubkey; no CA chain required. Used by station listeners running pubkey-anchored peering and by macula-net transport bring-up.

Get connection stats. NOT IMPLEMENTED — answers {error, not_implemented}.

Hand off a stream to another process (for macula_dist).

Complete TLS handshake. With Quinn, handshake completes during accept — this is a no-op for compat.

Listen on a port or {Address, Port} tuple.

Listen on a specific bind address and port. BindAddr is a binary: "0.0.0.0", "192.168.1.1", "2600:3c0e::100", etc.

Path MTU as discovered by Quinn's DPLPMTUD on this connection. Returns {ok, Bytes} once the path MTU has been established; {error, no_path_mtu} early in the connection lifecycle (before the first probe lands) or if the peer disabled datagrams. Phase 4.2.

Open a new bidirectional stream.

Open stream with options map (for macula_dist).

Get remote address of a connection.

Send data on a stream (blocking).

Set active mode on a stream handle.

Functions

accept_stream(Conn, Opts, Timeout)

-spec accept_stream(reference(), map(), timeout()) -> {ok, reference()} | {error, term()}.

Accept stream with options and timeout (for macula_dist).

async_accept(Listener)

-spec async_accept(reference()) -> ok | {error, term()}.

Start accepting connections on a listener. Delivers {quic, new_conn, ConnRef, Info} to the calling process.

async_accept(Listener, Opts)

-spec async_accept(reference(), map()) -> ok | {error, term()}.

async_accept_stream(Conn)

-spec async_accept_stream(reference()) -> ok | {error, term()}.

Start accepting streams on a connection. Delivers {quic, new_stream, StreamRef, #{conn => ConnRef}} to the owning process.

async_accept_stream(Conn, Opts)

-spec async_accept_stream(reference(), map()) -> ok | {error, term()}.

async_send(Stream, Data)

-spec async_send(reference(), iodata()) -> ok | {error, term()}.

Send data asynchronously.

async_shutdown_connection(Conn, Flag, Code)

-spec async_shutdown_connection(reference(), integer(), integer()) -> ok.

Async shutdown connection.

async_shutdown_stream(Stream, Flag, Code)

-spec async_shutdown_stream(reference(), integer(), integer()) -> ok.

Async shutdown stream.

close(Ref)

-spec close(reference()) -> ok.

Generic close — tries stream, then connection, then listener.

close_connection(Conn)

-spec close_connection(reference()) -> ok.

Close a connection.

close_listener(Listener)

-spec close_listener(reference()) -> ok.

Close a listener.

close_stream(Stream)

-spec close_stream(reference()) -> ok.

Close a stream.

connect(Host, Port, Opts, Timeout)

-spec connect(Host, inet:port_number(), list(), timeout()) -> {ok, reference()} | {error, term()}
                 when Host :: binary() | string().

Connect to a remote QUIC server. Host is a hostname or IP-string; validation depends on verify / verify_pubkey opts.

Trust modes (most to least authenticated):

  • {verify_pubkey, Pin} — pin the leaf cert's Ed25519 SPKI to Pin (32 bytes). No CA chain. Overrides verify.
  • {verify, webpki} — webpki roots + hostname check (Let's Encrypt-anchored station certs). THE DEFAULT since 5.0.0; before that the default was none.
  • {verify, none} — skip all server-cert verification. Development / self-signed labs only; a network MITM can impersonate the peer. Must now be opted into explicitly, and every such dial logs a warning.

controlling_process(Handle, Pid)

-spec controlling_process(reference(), pid()) -> ok | {error, term()}.

Transfer ownership of a handle to another process. Works with both stream and connection handles.

generate_self_signed_cert(Pubkey, Privkey, Sans)

-spec generate_self_signed_cert(Pubkey :: binary(), Privkey :: binary(), Sans :: [binary() | string()]) ->
                                   {ok, {CertPem :: binary(), KeyPem :: binary()}} | {error, term()}.

Generate a self-signed X.509 cert from an Ed25519 keypair. Returns {ok, {CertPem, KeyPem}} as PEM-encoded binaries suitable for handing to macula_quic:listen/3 via cert / key opts (after writing to disk). The cert wraps the identity's macula pubkey; no CA chain required. Used by station listeners running pubkey-anchored peering and by macula-net transport bring-up.

getstat(Conn, Stats)

-spec getstat(reference(), [atom()]) -> {error, not_implemented}.

Get connection stats. NOT IMPLEMENTED — answers {error, not_implemented}.

⚠ This used to answer {ok, [{S, 0} || S <- Stats]} — plausible, well-formed, permanently zero — and excuse itself with "zeroed values are harmless (dist_util only uses these for liveness signals)". That is precisely the use a hardcoded zero destroys. A counter that always reads zero makes "nothing is moving" indistinguishable from "nobody implemented the counter", so any liveness check built on it is green forever and its author cannot tell.

That is not hypothetical. On 2026-08-13 station-it-milan received every packet sent to it, answered none for thirty hours, and every signal derived from the BEAM read healthy. Anyone reaching for a send-side counter to catch that would have found this one, and it would have lied. Failing loudly is the only honest answer until the NIF surfaces the real thing.

Quinn HAS the numbers: quinn::Connection::stats() carries udp_tx{datagrams,bytes}, udp_rx{...} and path{rtt,lost_packets,black_holes_detected}, and nif_max_datagram_size already calls stats() and discards all but path.current_mtu. Surfacing the rest is an extension of a working function — see macula-station plans/PLAN_WIRE_LIVENESS_TRIPWIRE.md commit 5.

The sole consumer, macula_dist:quic_getstat/1, already has an {error, _} -> {ok, 0, 0, 0} branch, so this changes no behaviour there. It changes what the next caller is told.

handoff_stream(Stream, NewOwner, Opts)

-spec handoff_stream(reference(), pid(), map()) -> ok | {error, term()}.

Hand off a stream to another process (for macula_dist).

handshake(Conn)

-spec handshake(reference()) -> ok | {ok, reference()} | {error, term()}.

Complete TLS handshake. With Quinn, handshake completes during accept — this is a no-op for compat.

listen(Port, Opts)

-spec listen(inet:port_number() | {string() | binary(), inet:port_number()}, list()) ->
                {ok, reference()} | {error, term()}.

Listen on a port or {Address, Port} tuple.

listen(BindAddr, Port, Opts)

-spec listen(binary() | string(), inet:port_number(), list()) -> {ok, reference()} | {error, term()}.

Listen on a specific bind address and port. BindAddr is a binary: "0.0.0.0", "192.168.1.1", "2600:3c0e::100", etc.

max_datagram_size(Conn)

-spec max_datagram_size(reference()) -> {ok, pos_integer()} | {error, term()}.

Path MTU as discovered by Quinn's DPLPMTUD on this connection. Returns {ok, Bytes} once the path MTU has been established; {error, no_path_mtu} early in the connection lifecycle (before the first probe lands) or if the peer disabled datagrams. Phase 4.2.

open_stream(Conn)

-spec open_stream(reference()) -> {ok, reference()} | {error, term()}.

Open a new bidirectional stream.

open_stream(Conn, Opts)

-spec open_stream(reference(), map()) -> {ok, reference()} | {error, term()}.

Open stream with options map (for macula_dist).

peername(Conn)

-spec peername(reference()) -> {ok, {string(), inet:port_number()}} | {error, term()}.

Get remote address of a connection.

send(Stream, Data)

-spec send(reference(), iodata()) -> ok | {error, term()}.

Send data on a stream (blocking).

setopt(Stream, _, Value)

-spec setopt(reference(), active, boolean()) -> ok | {error, term()}.

Set active mode on a stream handle.