quic_dist (quic v1.3.0)
View SourceErlang distribution protocol implementation over QUIC.
This module implements the Erlang distribution protocol callbacks using QUIC as the transport layer. It provides:
- Connection establishment via TLS 1.3 (built into QUIC) - Multiple streams for parallel message delivery - Head-of-line blocking avoidance - Connection migration for NAT traversal - 0-RTT reconnection for fast session resumption
Configuration
Enable QUIC distribution in vm.args:
-proto_dist quic
-epmd_module quic_epmd
-start_epmd falseConfigure in sys.config:
{quic, [
{dist, [
{cert_file, "/path/to/cert.pem"},
{key_file, "/path/to/key.pem"},
{cacert_file, "/path/to/ca.pem"},
{verify, verify_peer}
]}
]}
Summary
Functions
Accept a connection from the distribution listener.
Handle an accepted connection. Called by net_kernel when a new connection is accepted.
Register to accept incoming user streams from a node. Joins the acceptor pool for the node. Multiple processes can register as acceptors. Incoming streams are assigned to acceptors using round-robin selection.
Return the address family to use.
Close the distribution listener.
Close a user stream gracefully. This sends a FIN to the peer. When both sides have sent FIN, the owner receives {quic_dist_stream, StreamRef, closed}.
Transfer stream ownership to another process. The new owner will receive all subsequent messages for this stream.
Get the distribution controller for a connected node. Returns {ok, ControllerPid} if the node is connected, {error, not_connected} otherwise.
Check if a node name is valid.
List all user streams across all connected nodes.
List user streams for a specific connected node.
Start listening for incoming distribution connections.
Start listening with options.
Open a bidirectional user stream to a connected node. Returns {ok, StreamRef} on success where StreamRef can be used with send/2,3 and close_stream/1. The caller becomes the stream owner.
Open a bidirectional user stream with options. Options: {priority, 16..255} - Stream priority (default: 128, lower = higher priority) Note: priorities 0-15 are reserved for distribution
Reset/cancel a user stream immediately (notifies peer). Uses default error code 0.
Reset/cancel a user stream with a specific error code. The peer receives the reset notification immediately.
Check if this distribution module should be used for the given node. Returns true if the node name is valid and we can potentially connect.
Send data on a user stream. Equivalent to send(StreamRef, Data, false).
Send data on a user stream. When Fin is true, this marks the end of data on this stream (half-close).
Set up an outgoing distribution connection. Called by net_kernel to establish a connection to another node.
Stop accepting incoming user streams from a node. Removes the calling process from the acceptor pool.
Types
-type stream_info() :: #{ref => stream_ref(), node => node(), stream_id => non_neg_integer(), owner => pid(), priority => 16..255, recv_fin => boolean(), send_fin => boolean()}.
-type stream_opt() :: {priority, 16..255}.
-type stream_ref() :: {quic_dist_stream, node(), non_neg_integer()}.
Functions
Accept a connection from the distribution listener.
-spec accept_connection(AcceptPid :: pid(), Socket :: term(), MyNode :: node(), Allowed :: term(), SetupTime :: non_neg_integer()) -> pid().
Handle an accepted connection. Called by net_kernel when a new connection is accepted.
Register to accept incoming user streams from a node. Joins the acceptor pool for the node. Multiple processes can register as acceptors. Incoming streams are assigned to acceptors using round-robin selection.
When a new stream arrives, one acceptor receives: {quic_dist_stream, StreamRef, {data, Data, Fin}}
The acceptor automatically becomes the stream owner (implicit ownership). Use controlling_process/2 to transfer ownership to a worker process.
If no acceptors are registered, incoming streams are refused with RESET.
-spec address() -> #net_address{address :: term(), host :: term(), protocol :: term(), family :: term()}.
Return the address family to use.
-spec close(Listen :: term()) -> ok.
Close the distribution listener.
-spec close_stream(StreamRef :: stream_ref()) -> ok | {error, term()}.
Close a user stream gracefully. This sends a FIN to the peer. When both sides have sent FIN, the owner receives {quic_dist_stream, StreamRef, closed}.
-spec controlling_process(StreamRef :: stream_ref(), NewOwner :: pid()) -> ok | {error, term()}.
Transfer stream ownership to another process. The new owner will receive all subsequent messages for this stream.
Get the distribution controller for a connected node. Returns {ok, ControllerPid} if the node is connected, {error, not_connected} otherwise.
Check if a node name is valid.
-spec list_streams() -> [stream_info()].
List all user streams across all connected nodes.
-spec list_streams(Node :: node()) -> [stream_info()].
List user streams for a specific connected node.
-spec listen(Name :: atom()) -> {ok, {LSocket :: term(), TcpAddress :: term(), Creation :: non_neg_integer()}} | {error, Reason :: term()}.
Start listening for incoming distribution connections.
-spec listen(Name :: atom(), Opts :: map()) -> {ok, {LSocket :: term(), TcpAddress :: term(), Creation :: non_neg_integer()}} | {error, Reason :: term()}.
Start listening with options.
-spec open_stream(Node :: node()) -> {ok, stream_ref()} | {error, term()}.
Open a bidirectional user stream to a connected node. Returns {ok, StreamRef} on success where StreamRef can be used with send/2,3 and close_stream/1. The caller becomes the stream owner.
-spec open_stream(Node :: node(), Options :: [stream_opt()]) -> {ok, stream_ref()} | {error, term()}.
Open a bidirectional user stream with options. Options: {priority, 16..255} - Stream priority (default: 128, lower = higher priority) Note: priorities 0-15 are reserved for distribution
-spec reset_stream(StreamRef :: stream_ref()) -> ok | {error, term()}.
Reset/cancel a user stream immediately (notifies peer). Uses default error code 0.
-spec reset_stream(StreamRef :: stream_ref(), ErrorCode :: non_neg_integer()) -> ok | {error, term()}.
Reset/cancel a user stream with a specific error code. The peer receives the reset notification immediately.
Check if this distribution module should be used for the given node. Returns true if the node name is valid and we can potentially connect.
-spec send(StreamRef :: stream_ref(), Data :: iodata()) -> ok | {error, term()}.
Send data on a user stream. Equivalent to send(StreamRef, Data, false).
-spec send(StreamRef :: stream_ref(), Data :: iodata(), Fin :: boolean()) -> ok | {error, term()}.
Send data on a user stream. When Fin is true, this marks the end of data on this stream (half-close).
-spec setup(Node :: node(), Type :: atom(), MyNode :: node(), LongOrShortNames :: shortnames | longnames, SetupTime :: non_neg_integer()) -> pid().
Set up an outgoing distribution connection. Called by net_kernel to establish a connection to another node.
Stop accepting incoming user streams from a node. Removes the calling process from the acceptor pool.