XGW.Peer.Datachannel (xgw v0.1.0)

Copy Markdown View Source

Per-Peer process that owns SCTP and DTLS application-data for data channels.

What problem this solves

Production datachannel egress used to run on the XGW.Peer GenServer mailbox together with ICE, RTP, and consent. Under fanout load, synchronous SctpAssociation.send/4 plus :ssl.send/2 queued behind (and blocked) those duties, so wire latency climbed into seconds. This process isolates SCTP and DTLS app-data: Forwarder casts land here, and Peer stays responsive for media.

Casts are drained in batches (default up to 32) so multiple user messages can share one flush of transmit events under load. Handler callbacks still use the Peer pid as peer_ref so Session and Forwarder identity is unchanged.

A full SCTP-in-ETS SendHandle hot path is not shipped (ssl_sock ownership).

RFCs

  • RFC 8261 -- SCTP over DTLS
  • RFC 8831 -- WebRTC data channels
  • RFC 8841 -- SDP negotiation of SCTP

Summary

Types

Opaque options for start_link/1.

Functions

Returns a specification to start this module under a supervisor.

Creates the ETS peer->Datachannel map (idempotent). Called from XGW.Application.

Looks up the Datachannel pid published for peer, if any.

Opens a local data channel after the association is connected.

Sends a user message and waits for SCTP/DTLS flush on this process.

Queues a user message on this Datachannel process (cast; batched drain).

Starts a Datachannel process for peer.

Types

start_opt()

@type start_opt() ::
  {:peer, pid()}
  | {:handler, pid()}
  | {:ssl_sock, term()}
  | {:role, :active | :passive}
  | {:assoc, XSockets.Sctp.Association.t()}
  | {:send_dtls, (map(), binary() -> :ok | {:error, term()})}
  | {:batch_max, pos_integer()}
  | {:sctp_ports, map()}

Opaque options for start_link/1.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

ensure_table!()

@spec ensure_table!() :: :ok

Creates the ETS peer->Datachannel map (idempotent). Called from XGW.Application.

lookup(peer)

@spec lookup(pid()) :: {:ok, pid()} | :error

Looks up the Datachannel pid published for peer, if any.

open_datachannel(dc, label, opts \\ [])

@spec open_datachannel(pid(), binary(), keyword()) :: {:ok, map()} | {:error, term()}

Opens a local data channel after the association is connected.

send_datachannel(dc, channel_ref, data, type \\ :string)

@spec send_datachannel(pid(), reference(), binary(), :string | :binary) ::
  :ok | {:error, term()}

Sends a user message and waits for SCTP/DTLS flush on this process.

send_datachannel_async(dc, channel_ref, data, type \\ :string)

@spec send_datachannel_async(pid(), reference(), binary(), :string | :binary) :: :ok

Queues a user message on this Datachannel process (cast; batched drain).

start_link(opts)

@spec start_link([start_opt()]) :: GenServer.on_start()

Starts a Datachannel process for peer.

When ssl_sock is present, takes over :ssl.controlling_process/2 so DTLS app-data messages arrive here. Optional :assoc injects an existing association (tests). Optional :send_dtls replaces :ssl.send/2 (tests).