quic (quic v1.3.0)
View SourceQUIC public API.
This module provides the public interface for QUIC connections. The API is compatible with hackney_quic for drop-in replacement.
Messages
Messages sent to owner process (Conn is the connection pid):
{quic, Conn, {connected, Info}}- Connection established{quic, Conn, {stream_opened, StreamId}}- Stream opened{quic, Conn, {closed, Reason}}- Connection closed{quic, Conn, {transport_error, Code, Reason}}- Transport error{quic, Conn, {stream_data, StreamId, Bin, Fin}}- Data received{quic, Conn, {stream_reset, StreamId, ErrorCode}}- Stream reset{quic, Conn, {stop_sending, StreamId, ErrorCode}}- Stop sending{quic, Conn, {goaway, LastStreamId, ErrorCode, Debug}}- GoAway received{quic, Conn, {session_ticket, Ticket}}- Session ticket for 0-RTT{quic, Conn, {send_ready, StreamId}}- Stream ready to write{quic, Conn, {timer, NextTimeoutMs}}- Timer notification{quic, Conn, {datagram, Data}}- Datagram received (RFC 9221){quic, Conn, {stream_deadline, StreamId}}- Stream deadline expired
Summary
Functions
Cancel a stream deadline. Returns ok if the deadline was cancelled, or {error, not_found} if no deadline exists.
Close a QUIC connection with normal reason.
Close a QUIC connection with the given reason. An integer is treated as an application error code (RFC 9000 §19.19) and sent verbatim in the CONNECTION_CLOSE frame; any other term keeps its historical pass-through behaviour.
Close a QUIC connection with application error code and reason phrase. ErrorCode is a 62-bit unsigned integer (RFC 9000). Reason is the reason phrase sent in the CONNECTION_CLOSE frame.
Connect to a QUIC server. Returns {ok, Conn} on success where Conn is a pid(). The owner process will receive {quic, Conn, {connected, Info}} when the connection is established.
Get maximum datagram payload size. Returns 0 if peer doesn't support datagrams (RFC 9221). The returned size is the peer's advertised max_datagram_frame_size.
Get datagram accounting counters. Returns delivered / dropped_recv / sent / dropped_send counters so callers can detect back-pressure when datagram_recv_queue_len has been set to a finite value.
Get the file descriptor from a gen_udp socket. This can be used to pass an existing UDP socket to connect/4 via the socket_fd option.
Get the current MTU for a connection.
Get the peer's transport parameters.
Get send queue information for a connection. This can be used by distribution controllers or other high-level protocols to implement backpressure based on queue state.
Get the list of connection PIDs for a named server.
Get information about a named server.
Get the listening port of a named server.
Get connection statistics for liveness detection.
Get the remaining time for a stream deadline. Returns {ok, {RemainingMs, Action}} where RemainingMs is milliseconds until expiry. Returns {error, no_deadline} if no deadline is set.
Get the priority for a stream. Returns {ok, {Urgency, Incremental}} or {error, not_found}.
Handle connection timeout. Should be called when timer expires. Returns next timeout in ms or 'infinity'.
Check if QUIC support is available. Always returns true for pure Erlang implementation.
Trigger connection migration to a new local address. This initiates path validation on a new network path. The connection will send PATH_CHALLENGE and wait for PATH_RESPONSE.
Trigger connection migration with options. This initiates path validation on a new network path. The connection will send PATH_CHALLENGE and wait for PATH_RESPONSE.
Open a new bidirectional stream. Returns {ok, StreamId} on success.
Open a new unidirectional stream. Returns {ok, StreamId} on success. Unidirectional streams are send-only for the initiator.
Get the peer certificate. Returns the DER-encoded certificate of the peer if available.
Get the remote address of the connection.
Process pending QUIC events. This is called automatically by the connection process.
Reset a stream with an error code.
Reset a stream with reliable delivery up to specified size. Data up to ReliableSize will be delivered before the reset takes effect. Requires peer support for the reliable stream reset extension (draft-ietf-quic-reliable-stream-reset-07). ReliableSize must be less than or equal to the amount of data already sent.
Send data on a stream. Fin indicates if this is the final frame on the stream.
Send data on a stream with a timeout. Fin indicates if this is the final frame on the stream. Timeout is in milliseconds; if the operation takes longer, returns {error, timeout}.
Send data on a stream asynchronously (fire-and-forget). This is faster than send_data/4 because it uses cast instead of call, avoiding the round-trip latency. However, errors are silently dropped. Use this for high-throughput scenarios where occasional dropped data is acceptable.
Send a datagram on the connection. Datagrams are unreliable and may be lost.
Send a PING frame on the connection.
Return a child spec for embedding a QUIC server in your own supervisor.
Set the congestion control algorithm for a connection. This changes the algorithm on a live connection. The new algorithm starts fresh (cwnd, ssthresh reset to defaults). Only works in connected state.
Set the owner process for a connection. Similar to gen_tcp:controlling_process/2.
Set the owner process for a connection (synchronous). Use this when you need to ensure ownership is transferred before continuing.
Set a deadline for a stream. TimeoutMs is the number of milliseconds from now until the deadline expires. When the deadline expires, the stream will be reset and/or the owner will be notified. Default action is 'both' (notify + reset).
Set a deadline for a stream with options. TimeoutMs is the number of milliseconds from now until the deadline expires.
Set the priority for a stream. Urgency: 0-7 (lower = more urgent, default 3) Incremental: boolean (data can be processed incrementally, default false) Per RFC 9218 (Extensible Priorities for HTTP).
Set connection options.
Get the local address of the connection.
Start a named QUIC server on the specified port.
Request peer to stop sending on a stream. Sends a STOP_SENDING frame (RFC 9000 Section 19.5).
Stop a named QUIC server.
List all running server names.
Types
-type send_queue_info() :: #{bytes := non_neg_integer(), cwnd := non_neg_integer(), in_flight := non_neg_integer(), in_recovery := boolean(), congested := boolean()}.
Functions
-spec cancel_stream_deadline(Conn, StreamId) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer().
Cancel a stream deadline. Returns ok if the deadline was cancelled, or {error, not_found} if no deadline exists.
-spec close(Conn) -> ok when Conn :: pid().
Close a QUIC connection with normal reason.
-spec close(Conn, Reason) -> ok when Conn :: pid(), Reason :: non_neg_integer() | term().
Close a QUIC connection with the given reason. An integer is treated as an application error code (RFC 9000 §19.19) and sent verbatim in the CONNECTION_CLOSE frame; any other term keeps its historical pass-through behaviour.
-spec close(Conn, ErrorCode, Reason) -> ok when Conn :: pid(), ErrorCode :: 0..4611686018427387903, Reason :: binary().
Close a QUIC connection with application error code and reason phrase. ErrorCode is a 62-bit unsigned integer (RFC 9000). Reason is the reason phrase sent in the CONNECTION_CLOSE frame.
-spec connect(Host, Port, Opts, Owner) -> {ok, pid()} | {error, term()} when Host :: binary() | string(), Port :: inet:port_number(), Opts :: map(), Owner :: pid().
Connect to a QUIC server. Returns {ok, Conn} on success where Conn is a pid(). The owner process will receive {quic, Conn, {connected, Info}} when the connection is established.
Options:
socket- Use an existing UDP socket (gen_udp:socket())extra_socket_opts- Options for socket creation (e.g., [{ip, Addr}])verify- Verify server certificate (default: false)alpn- ALPN protocols (default: [<<"h3">>])server_name- Server Name Indication (default: Host)
-spec datagram_max_size(Conn) -> non_neg_integer() | {error, term()} when Conn :: pid().
Get maximum datagram payload size. Returns 0 if peer doesn't support datagrams (RFC 9221). The returned size is the peer's advertised max_datagram_frame_size.
-spec datagram_stats(Conn) -> #{delivered := non_neg_integer(), dropped_recv := non_neg_integer(), sent := non_neg_integer(), dropped_send := non_neg_integer()} when Conn :: pid().
Get datagram accounting counters. Returns delivered / dropped_recv / sent / dropped_send counters so callers can detect back-pressure when datagram_recv_queue_len has been set to a finite value.
-spec get_fd(gen_udp:socket()) -> {ok, integer()} | {error, term()}.
Get the file descriptor from a gen_udp socket. This can be used to pass an existing UDP socket to connect/4 via the socket_fd option.
-spec get_mtu(Conn) -> {ok, pos_integer()} | {error, term()} when Conn :: pid().
Get the current MTU for a connection.
Returns the effective MTU discovered via DPLPMTUD (RFC 8899). The MTU starts at 1200 bytes (QUIC minimum) and is probed up to the peer's max_udp_payload_size or local configuration.
Returns {ok, MTU} where MTU is the current maximum packet size, or {error, not_found} if the connection doesn't exist.
Get the peer's transport parameters.
Returns the transport parameters received from the peer during handshake. Useful for verifying peer capabilities such as WebTransport support (e.g., checking for reset_stream_at transport parameter).
Returns {ok, TransportParams} where TransportParams is a map of the peer's advertised transport parameters.
-spec get_send_queue_info(Conn) -> {ok, send_queue_info()} | {error, term()} when Conn :: pid().
Get send queue information for a connection. This can be used by distribution controllers or other high-level protocols to implement backpressure based on queue state.
Returns a map with: - bytes: Current bytes in send queue - cwnd: Congestion window size - in_flight: Bytes sent but not acknowledged - in_recovery: Whether in congestion recovery - congested: Whether backpressure should be applied
See quic_dist_controller for usage example.
Get the list of connection PIDs for a named server.
Get information about a named server.
Returns a map containing:
pid- Server supervisor PIDport- Listening portopts- Server optionsstarted_at- Start timestamp in milliseconds
-spec get_server_port(Name) -> {ok, inet:port_number()} | {error, not_found} when Name :: atom().
Get the listening port of a named server.
Useful when the server was started with port 0 (ephemeral port).
Get connection statistics for liveness detection.
Returns packet counts that can be used by net_kernel for tick checking. Any QUIC packet (ACK, PING, data) counts as proof of peer liveness.
Returns a map with: - packets_received: Total QUIC packets successfully received - packets_sent: Total QUIC packets sent - data_received: Total bytes of application data received - data_sent: Total bytes of application data sent
See quic_dist_controller for usage in distribution tick checking.
-spec get_stream_deadline(Conn, StreamId) -> {ok, {non_neg_integer() | infinity, reset | notify | both}} | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer().
Get the remaining time for a stream deadline. Returns {ok, {RemainingMs, Action}} where RemainingMs is milliseconds until expiry. Returns {error, no_deadline} if no deadline is set.
-spec get_stream_priority(Conn, StreamId) -> {ok, {0..7, boolean()}} | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer().
Get the priority for a stream. Returns {ok, {Urgency, Incremental}} or {error, not_found}.
-spec handle_timeout(Conn, NowMs) -> non_neg_integer() | infinity when Conn :: pid(), NowMs :: non_neg_integer().
Handle connection timeout. Should be called when timer expires. Returns next timeout in ms or 'infinity'.
-spec is_available() -> boolean().
Check if QUIC support is available. Always returns true for pure Erlang implementation.
Trigger connection migration to a new local address. This initiates path validation on a new network path. The connection will send PATH_CHALLENGE and wait for PATH_RESPONSE.
-spec migrate(Conn, Opts) -> ok | {error, term()} when Conn :: pid(), Opts :: #{timeout => pos_integer()}.
Trigger connection migration with options. This initiates path validation on a new network path. The connection will send PATH_CHALLENGE and wait for PATH_RESPONSE.
Options:
timeout- Timeout in milliseconds for the gen_statem call (default: 5000)
-spec open_stream(Conn) -> {ok, non_neg_integer()} | {error, term()} when Conn :: pid().
Open a new bidirectional stream. Returns {ok, StreamId} on success.
-spec open_unidirectional_stream(Conn) -> {ok, non_neg_integer()} | {error, term()} when Conn :: pid().
Open a new unidirectional stream. Returns {ok, StreamId} on success. Unidirectional streams are send-only for the initiator.
Get the peer certificate. Returns the DER-encoded certificate of the peer if available.
-spec peername(Conn) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, term()} when Conn :: pid().
Get the remote address of the connection.
-spec process(Conn) -> ok when Conn :: pid().
Process pending QUIC events. This is called automatically by the connection process.
-spec reset_stream(Conn, StreamId, ErrorCode) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), ErrorCode :: non_neg_integer().
Reset a stream with an error code.
-spec reset_stream_at(Conn, StreamId, ErrorCode, ReliableSize) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), ErrorCode :: non_neg_integer(), ReliableSize :: non_neg_integer().
Reset a stream with reliable delivery up to specified size. Data up to ReliableSize will be delivered before the reset takes effect. Requires peer support for the reliable stream reset extension (draft-ietf-quic-reliable-stream-reset-07). ReliableSize must be less than or equal to the amount of data already sent.
-spec send_data(Conn, StreamId, Data, Fin) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), Data :: iodata(), Fin :: boolean().
Send data on a stream. Fin indicates if this is the final frame on the stream.
-spec send_data(Conn, StreamId, Data, Fin, Timeout) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), Data :: iodata(), Fin :: boolean(), Timeout :: timeout().
Send data on a stream with a timeout. Fin indicates if this is the final frame on the stream. Timeout is in milliseconds; if the operation takes longer, returns {error, timeout}.
-spec send_data_async(Conn, StreamId, Data, Fin) -> ok when Conn :: pid(), StreamId :: non_neg_integer(), Data :: iodata(), Fin :: boolean().
Send data on a stream asynchronously (fire-and-forget). This is faster than send_data/4 because it uses cast instead of call, avoiding the round-trip latency. However, errors are silently dropped. Use this for high-throughput scenarios where occasional dropped data is acceptable.
Send a datagram on the connection. Datagrams are unreliable and may be lost.
Send a PING frame on the connection.
PING frames are transport-level frames that bypass congestion control. They elicit an ACK from the peer and can be used for liveness checking. This is useful for distribution tick messages that must get through even when the connection is congested.
Returns ok if the PING was sent, or {error, Reason} if it failed.
-spec server_spec(Name, Port, Opts) -> supervisor:child_spec() when Name :: atom(), Port :: inet:port_number(), Opts :: map().
Return a child spec for embedding a QUIC server in your own supervisor.
This allows you to supervise QUIC servers within your application's supervision tree instead of using the built-in server management.
Example:
init([]) ->
Spec = quic:server_spec(my_quic, 4433, #{
cert => CertDer,
key => KeyTerm,
alpn => [<<"h3">>]
}),
{ok, {#{strategy => one_for_one}, [Spec]}}.
-spec set_congestion_control(Conn, Algorithm) -> ok | {error, term()} when Conn :: pid(), Algorithm :: newreno | bbr | cubic.
Set the congestion control algorithm for a connection. This changes the algorithm on a live connection. The new algorithm starts fresh (cwnd, ssthresh reset to defaults). Only works in connected state.
Algorithm: newreno | bbr | cubic
Set the owner process for a connection. Similar to gen_tcp:controlling_process/2.
Set the owner process for a connection (synchronous). Use this when you need to ensure ownership is transferred before continuing.
-spec set_stream_deadline(Conn, StreamId, TimeoutMs) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), TimeoutMs :: pos_integer().
Set a deadline for a stream. TimeoutMs is the number of milliseconds from now until the deadline expires. When the deadline expires, the stream will be reset and/or the owner will be notified. Default action is 'both' (notify + reset).
-spec set_stream_deadline(Conn, StreamId, TimeoutMs, Opts) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), TimeoutMs :: pos_integer(), Opts :: #{action => reset | notify | both, error_code => non_neg_integer()}.
Set a deadline for a stream with options. TimeoutMs is the number of milliseconds from now until the deadline expires.
Options: - action: What to do when deadline expires: - notify: Send {quic, Conn, {stream_deadline, StreamId}} to owner - reset: Send RESET_STREAM and clean up - both (default): Notify AND reset - error_code: Error code for RESET_STREAM (default: 16#FF)
-spec set_stream_priority(Conn, StreamId, Urgency, Incremental) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), Urgency :: 0..7, Incremental :: boolean().
Set the priority for a stream. Urgency: 0-7 (lower = more urgent, default 3) Incremental: boolean (data can be processed incrementally, default false) Per RFC 9218 (Extensible Priorities for HTTP).
Set connection options.
-spec sockname(Conn) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, term()} when Conn :: pid().
Get the local address of the connection.
-spec start_server(Name, Port, Opts) -> {ok, pid()} | {error, term()} when Name :: atom(), Port :: inet:port_number(), Opts :: map().
Start a named QUIC server on the specified port.
Creates a listener pool that accepts incoming QUIC connections. Multiple named servers can run on different ports.
Options:
cert- DER-encoded certificate (required)key- Private key term (required)alpn- List of ALPN protocols (default: [<<"h3">>])pool_size- Number of listener processes (default: 1)connection_handler- Fun(Conn) -> {ok, HandlerPid} where Conn is the pid
Example:
{ok, _} = quic:start_server(my_server, 4433, #{
cert => CertDer,
key => KeyTerm,
alpn => [<<"h3">>],
pool_size => 4
}).
-spec stop_sending(Conn, StreamId, ErrorCode) -> ok | {error, term()} when Conn :: pid(), StreamId :: non_neg_integer(), ErrorCode :: non_neg_integer().
Request peer to stop sending on a stream. Sends a STOP_SENDING frame (RFC 9000 Section 19.5).
Stop a named QUIC server.
Stops the server and all its connections. The port will be freed for reuse.
-spec which_servers() -> [atom()].
List all running server names.