Xirsys.Sockets.SctpAssociation (xturn_sockets v2.2.1)

View Source

WebRTC SCTP association over a caller-owned byte pipe (typically DTLS application data).

What problem this solves

WebRTC data channels run SCTP encapsulated in DTLS, not raw SCTP over IP. This module drives an SCTP association in sans-IO mode via ex_sctp: the caller feeds inbound DTLS plaintext with handle_packet/2 and must send every {:transmit, packets} event back on the DTLS socket. DCEP negotiation and user messages are surfaced as events (:connected, {:channel_open, ...}, {:message, ...}).

This is not Transport.SCTP (OTP :gen_sctp over IP).

Requires the optional Hex dependency ex_sctp (Rust toolchain to compile).

RFCs

Summary

Types

One negotiated WebRTC data channel.

Events returned to the caller after IO or timeout.

t()

Opaque SCTP association state.

Functions

Returns true when the ex_sctp NIF is loaded and SCTP associations can run.

Starts SCTP as the association initiator (DTLS client / offerer side).

Returns channel metadata for ref, or nil when the channel is unknown.

Feeds one plaintext SCTP packet received from the peer (e.g. DTLS :ssl data).

Handles a previously scheduled SCTP timeout ({:timeout, ms} event).

Creates a new SCTP association in :new state.

Opens a local data channel (DCEP DataChannelOpen) after the association is connected.

Sends a user message on an open channel.

Types

channel()

@type channel() :: %{
  ref: reference(),
  id: non_neg_integer() | nil,
  label: String.t(),
  ordered: boolean(),
  reliability: :reliable | :rexmit | :timed,
  param: non_neg_integer(),
  protocol: String.t(),
  ready_state: :connecting | :open | :closed
}

One negotiated WebRTC data channel.

Fields

  • ref - caller-facing channel reference
  • id - SCTP stream id (even for offerer, odd for answerer, per role)
  • label - DCEP channel label
  • ordered - whether messages preserve order on this stream
  • reliability - DCEP reliability (:reliable, :rexmit, or :timed)
  • param - retransmit count or lifetime ms from DCEP
  • protocol - subprotocol string from DCEP Open
  • ready_state - :connecting, :open, or :closed

event()

@type event() ::
  :connected
  | :disconnected
  | {:transmit, [binary()]}
  | {:timeout, non_neg_integer() | nil}
  | {:channel_open, reference(), String.t(), non_neg_integer(), map()}
  | {:message, reference(), binary()}
  | {:channel_closed, reference()}

Events returned to the caller after IO or timeout.

Variants

  • :connected - SCTP association established
  • :disconnected - association closed
  • {:transmit, packets} - SCTP packets to send on the DTLS socket
  • {:timeout, ms} - schedule handle_timeout/1 after ms (or nil to cancel)
  • {:channel_open, ref, label, id, meta} - data channel ready; meta has :reliability, :order, and :param from DCEP
  • {:message, ref, payload} - user message on an open channel
  • {:channel_closed, ref} - remote closed the stream

t()

@type t() :: %{
  ref: reference(),
  state: :new | :connecting | :connected | :closed,
  id_type: :even | :odd | nil,
  channels: %{optional(reference()) => channel()},
  timer: reference() | nil
}

Opaque SCTP association state.

Fields

  • ref - ex_sctp NIF handle
  • state - association lifecycle (:new, :connecting, :connected, :closed)
  • id_type - even/odd stream id policy for DTLS client/server roles
  • channels - map of channel ref to channel/0
  • timer - optional timeout timer ref from {:timeout, ms} events

Functions

available?()

@spec available?() :: boolean()

Returns true when the ex_sctp NIF is loaded and SCTP associations can run.

connect(assoc)

@spec connect(t()) :: {[event()], t()}

Starts SCTP as the association initiator (DTLS client / offerer side).

Only valid when state is :new. Returns events (typically {:transmit, ...}) and updated association state.

get_channel(assoc, ref)

@spec get_channel(t(), reference()) :: channel() | nil

Returns channel metadata for ref, or nil when the channel is unknown.

handle_packet(assoc, data)

@spec handle_packet(t(), binary()) :: {[event()], t()}

Feeds one plaintext SCTP packet received from the peer (e.g. DTLS :ssl data).

Returns all pending events after processing the chunk. No-op when the association is :closed.

handle_timeout(assoc)

@spec handle_timeout(t()) :: {[event()], t()}

Handles a previously scheduled SCTP timeout ({:timeout, ms} event).

Call when the timer from a {:timeout, ms} event fires.

new(opts \\ [])

@spec new(keyword()) :: t()

Creates a new SCTP association in :new state.

Options

  • :role - :active (even stream ids; call connect/1) or :passive (odd ids; wait for peer INIT). Default :passive.

open_channel(assoc, label, opts \\ [])

@spec open_channel(t(), String.t(), keyword()) ::
  {[event()], reference(), t()} | {:error, atom(), t()}

Opens a local data channel (DCEP DataChannelOpen) after the association is connected.

Returns {events, channel_ref, assoc} or {:error, reason, assoc}.

send(assoc, channel_ref, data, type \\ :string)

@spec send(t(), reference(), binary(), :string | :binary) ::
  {[event()], t()} | {:error, atom(), t()}

Sends a user message on an open channel.

type is :string (PPI 51) or :binary (PPI 53).