glquic

QUIC connections, listeners and streams, built on erlang_quic.

Each connection sends its events, including those of all its streams, as messages to the process that owns it: the process that connected, or the one a listener’s handler returned, until ownership is transferred with transfer_connection. Receive them with receive, or add them to a selector with select.

import glquic

pub fn main() {
  let options = glquic.client_options(alpn: ["echo"])
  let assert Ok(connection) =
    glquic.connect(to: "localhost", on: 4433, with: options, timeout: 5000)
  let assert Ok(stream) = glquic.open_stream(connection)
  let assert Ok(Nil) = glquic.send_and_finish(stream, <<"Hello, Joe!">>)
  let assert Ok(glquic.Data(data: <<"Hello, Joe!">>, ..)) = glquic.receive(5000)
}

Types

A local or remote socket address.

pub type Address {
  Address(host: String, port: Int)
}

Constructors

  • Address(host: String, port: Int)

Marks options for connecting.

pub type Client

Why a connection closed.

pub type CloseReason {
  ClosedLocally(error_code: Int)
  ClosedByPeer(error_code: Int)
  PeerTransportError(error_code: Int, reason: String)
  IdleTimeout
  CertificateInvalid(reason: String)
  NoApplicationProtocol
  OtherReason(reason: String)
}

Constructors

  • ClosedLocally(error_code: Int)

    This side closed the connection with an application error code.

  • ClosedByPeer(error_code: Int)

    The peer closed the connection with an application error code.

  • PeerTransportError(error_code: Int, reason: String)

    The peer closed the connection with a transport or TLS error code, for example when no application protocol (ALPN) matched.

  • IdleTimeout

    Nothing was received within the idle timeout.

  • CertificateInvalid(reason: String)

    The peer’s certificate could not be verified.

  • NoApplicationProtocol

    The server accepted none of the client’s application protocols (ALPN).

  • OtherReason(reason: String)

    A reason not covered by the other variants, formatted as Erlang.

A QUIC connection to a peer.

pub type Connection

Errors returned by QUIC operations.

pub type Error {
  Timeout
  Closed
  HandshakeFailed(reason: CloseReason)
  NotConnected
  UnknownStream
  StreamClosed
  StreamLimitReached
  SendQueueFull
  DatagramsNotSupported
  DatagramTooLarge
  CongestionLimited
  AddressInUse
  NotFound
  CertificateError(String)
  Other(String)
}

Constructors

  • Timeout

    The operation did not finish in time.

  • Closed

    The connection has closed.

  • HandshakeFailed(reason: CloseReason)

    The connection closed before its handshake completed.

  • NotConnected

    The connection has not completed its handshake.

  • UnknownStream

    The connection has no stream with this ID.

  • StreamClosed

    The stream has already been closed.

  • StreamLimitReached

    The peer does not allow any more streams to be opened yet.

  • SendQueueFull

    The connection’s send queue is full and nothing was sent. Try again once it drains, for example after notify_when_send_ready.

  • DatagramsNotSupported

    The peer has not enabled datagrams.

  • DatagramTooLarge

    The datagram is larger than the peer accepts.

  • CongestionLimited

    The datagram was dropped by congestion control.

  • AddressInUse

    The UDP port is already in use.

  • NotFound

    The listener does not exist.

  • CertificateError(String)

    A certificate or private key file could not be read.

  • Other(String)

    An error not covered by the other variants, formatted as Erlang.

An event sent to the owner of a connection.

pub type Event {
  Connected(connection: Connection)
  NewStream(stream: Stream, unidirectional: Bool)
  Data(stream: Stream, data: BitArray, fin: Bool)
  StreamReset(stream: Stream, error_code: Int)
  StopSending(stream: Stream, error_code: Int)
  Datagram(connection: Connection, data: BitArray)
  SendReady(connection: Connection)
  TransportError(
    connection: Connection,
    error_code: Int,
    reason: String,
  )
  ConnectionClosed(connection: Connection, reason: CloseReason)
  Unknown(message: dynamic.Dynamic)
}

Constructors

  • Connected(connection: Connection)

    A connection completed its handshake.

  • NewStream(stream: Stream, unidirectional: Bool)

    The peer opened a stream.

  • Data(stream: Stream, data: BitArray, fin: Bool)

    Data was received on a stream. fin is true for the last data the peer will send on it.

  • StreamReset(stream: Stream, error_code: Int)

    The peer abruptly stopped sending on a stream.

  • StopSending(stream: Stream, error_code: Int)

    The peer asked this side to stop sending on a stream.

  • Datagram(connection: Connection, data: BitArray)

    A datagram was received on a connection.

  • SendReady(connection: Connection)

    The connection’s send queue has drained after notify_when_send_ready.

  • TransportError(
      connection: Connection,
      error_code: Int,
      reason: String,
    )

    A connection hit a transport error.

  • ConnectionClosed(connection: Connection, reason: CloseReason)

    A connection closed.

  • Unknown(message: dynamic.Dynamic)

    A quic message this library does not decode.

How a stream gives the peer credit to send more data.

pub type FlowControl {
  Automatic
  Manual
}

Constructors

  • Automatic

    Give credit as data is delivered to the owner, as long as the owner’s mailbox is not backed up.

  • Manual

    Only give credit for data returned with consume.

A listener accepting incoming connections on a UDP port.

pub type Listener

Connection options for a client or server.

pub opaque type Options(side)

Marks options for listening.

pub type Server

A stream within a connection, identified by its QUIC stream ID.

pub type Stream {
  Stream(connection: Connection, id: Int)
}

Constructors

Values

pub fn ca_certificate(
  options: Options(Client),
  path: String,
) -> Options(Client)

Verify the server certificate against the CA certificates in a PEM file.

pub fn client_certificate(
  options: Options(Client),
  certificate certificate: String,
  private_key private_key: String,
) -> Options(Client)

Present a PEM certificate and private key to the server.

pub fn client_options(alpn alpn: List(String)) -> Options(Client)

Options for connecting with the given application protocols (ALPN).

The server certificate is verified against the system certificate store, or the file set with ca_certificate.

pub fn close(
  connection: Connection,
  error_code: Int,
) -> Result(Nil, Error)

Close a connection, sending the peer an application error code. The owner receives ConnectionClosed when it is done.

pub fn close_listener(listener: Listener) -> Result(Nil, Error)

Stop a listener, closing the connections it accepted.

pub fn connect(
  to host: String,
  on port: Int,
  with options: Options(Client),
  timeout timeout: Int,
) -> Result(Connection, Error)

Connect to a server, waiting up to timeout milliseconds for the handshake. The calling process owns the connection.

pub fn consume(stream: Stream, bytes: Int) -> Result(Nil, Error)

Give the peer credit for this many bytes of processed data on a stream with Manual flow control.

pub fn datagrams(
  options: Options(side),
  enabled: Bool,
) -> Options(side)

Allow the peer to send datagrams.

pub fn finish(stream: Stream) -> Result(Nil, Error)

Finish sending on a stream. The peer receives the end of the stream after any data already sent.

pub fn idle_timeout(
  options: Options(side),
  milliseconds: Int,
) -> Options(side)

Close the connection after this many milliseconds without activity. Defaults to 30 seconds.

pub fn insecure_skip_verify(
  options: Options(Client),
) -> Options(Client)

Skip verifying the server certificate. Only use this for testing.

pub fn keep_alive_interval(
  options: Options(side),
  milliseconds: Int,
) -> Options(side)

Send a keep-alive packet after this many milliseconds without activity, at least 5000.

pub fn listen(
  on port: Int,
  with options: Options(Server),
  handler handler: fn(Connection) -> process.Pid,
) -> Result(Listener, Error)

Start listening on a UDP port. Use port 0 to pick any free port, and listener_address to find out which.

handler is called with each new connection before its handshake, and returns the process that will own it, for example one it spawns to handle the connection. It runs in the listener’s process, so it should return quickly. A connection closes when its owner exits.

pub fn listener_address(
  listener: Listener,
) -> Result(Address, Error)

The address a listener is bound to.

pub fn local_address(
  connection: Connection,
) -> Result(Address, Error)

The local address of a connection.

pub fn max_peer_bidirectional_streams(
  options: Options(side),
  count: Int,
) -> Options(side)

How many bidirectional streams the peer may have open at a time. Defaults to 100.

pub fn max_peer_unidirectional_streams(
  options: Options(side),
  count: Int,
) -> Options(side)

How many unidirectional streams the peer may have open at a time. Defaults to 100.

pub fn negotiated_protocol(
  connection: Connection,
) -> Result(String, Error)

The application protocol (ALPN) both sides agreed on.

pub fn notify_when_send_ready(
  connection: Connection,
) -> Result(Nil, Error)

Send the owner SendReady once the connection’s send queue has drained, for example after a send fails with SendQueueFull.

pub fn open_stream(
  connection: Connection,
) -> Result(Stream, Error)

Open a bidirectional stream.

pub fn open_unidirectional_stream(
  connection: Connection,
) -> Result(Stream, Error)

Open a stream that only this side can send on.

pub fn peer_address(
  connection: Connection,
) -> Result(Address, Error)

The remote address of a connection.

pub fn raw_option(
  options: Options(side),
  name: String,
  value: dynamic.Dynamic,
) -> Options(side)

Set an erlang_quic option that has no function of its own. See the options of quic:connect/4 and quic:start_server/3 for what is available.

pub fn receive(within timeout: Int) -> Result(Event, Nil)

Wait up to timeout milliseconds for a QUIC event.

pub fn require_client_certificate(
  options: Options(Server),
  ca_certificate path: String,
) -> Options(Server)

Require clients to present a certificate signed by a CA in a PEM file.

pub fn reset(
  stream: Stream,
  error_code: Int,
) -> Result(Nil, Error)

Abruptly stop sending on a stream, sending the peer an application error code.

pub fn select(
  selector: process.Selector(message),
  mapping: fn(Event) -> message,
) -> process.Selector(message)

Add a handler for QUIC events to a selector.

pub fn send(stream: Stream, data: BitArray) -> Result(Nil, Error)

Send data on a stream.

pub fn send_and_finish(
  stream: Stream,
  data: BitArray,
) -> Result(Nil, Error)

Send data on a stream and finish sending on it.

pub fn send_datagram(
  connection: Connection,
  data: BitArray,
) -> Result(Nil, Error)

Send an unreliable datagram. The peer must have enabled datagrams.

pub fn server_options(
  alpn alpn: List(String),
  certificate certificate: String,
  private_key private_key: String,
) -> Options(Server)

Options for listening with the given application protocols (ALPN) and a PEM certificate and private key. The certificate file may also hold the rest of its chain.

Client certificates are not requested unless require_client_certificate is set.

pub fn set_flow_control(
  stream: Stream,
  mode: FlowControl,
) -> Result(Nil, Error)

Change how a stream gives the peer credit to send more data, for example to apply backpressure while data is processed elsewhere.

pub fn stop_sending(
  stream: Stream,
  error_code: Int,
) -> Result(Nil, Error)

Ask the peer to stop sending on a stream, with an application error code.

pub fn transfer_connection(
  connection: Connection,
  to owner: process.Pid,
) -> Result(Nil, Error)

Make another process the owner of a connection, so it receives the events of the connection and all its streams. A connected connection sends the new owner Connected.

Events already sent to the old owner stay in its mailbox, so prefer returning the final owner from a listener’s handler.

✨ Search Document