Xirsys.XTurn.Plugin behaviour (xturn_plugin_api v0.1.1)

Copy Markdown View Source

Behaviour for XTurn data-plane plugins.

What problem this solves

A TURN relay forwards media between a client and remote peers. Operators sometimes need to inspect or meter that traffic (abuse guard, QoS counters) without forking the server. Plugins implement this behaviour; xturn attaches them per allocation and calls them on each relayed frame.

This package is only the contract (Plugin, Allocation, Frame). Concrete plugins live in packages such as xturn-plugins.

Modes

  • :active - handle_frame/3 may return {:ok, binary}, :drop, or {:error, term}. Called concurrently from many processes; keep mutable state outside the returned state (for example ETS).
  • :passive - handle_frame/3 returns {:ok, new_state} and runs in a dedicated instance process (safe for timers via handle_info/2).

Main modules

RFCs

Plugins sit on the TURN data path (Send Indication, ChannelData, Data Indication). They do not replace STUN/TURN signaling.

Summary

Types

Relay direction relative to the TURN client.

How the payload was carried on the TURN wire.

Callbacks

Called once per allocation, at allocation time.

Allocation teardown. Flush and close here. Once only.

Per-frame callback.

Optional message handler for passive plugins.

Which directions this plugin wants. Never called for others.

Called once per attached allocation.

Fixed for the lifetime of the module: :active or :passive.

Types

direction()

@type direction() :: :egress | :ingress

Relay direction relative to the TURN client.

  • :egress - client toward peer (Send Indication / ChannelData outbound)
  • :ingress - peer toward client (Data Indication / ChannelData inbound)

framing()

@type framing() :: :send_indication | :channel_data | :data_indication

How the payload was carried on the TURN wire.

  • :send_indication - TURN Send Indication
  • :channel_data - TURN ChannelData
  • :data_indication - TURN Data Indication

Callbacks

attach?(t, keyword)

@callback attach?(
  Xirsys.XTurn.Plugin.Allocation.t(),
  keyword()
) :: boolean()

Called once per allocation, at allocation time.

Return false and no instance is created and nothing is added to this allocation's chain.

handle_close(reason, state)

(optional)
@callback handle_close(reason :: term(), state :: term()) :: :ok

Allocation teardown. Flush and close here. Once only.

handle_frame(payload, t, state)

@callback handle_frame(
  payload :: binary(),
  Xirsys.XTurn.Plugin.Frame.t(),
  state :: term()
) ::
  {:ok, binary()} | :drop | {:error, term()} | {:ok, new_state :: term()}

Per-frame callback.

  • :active - must return {:ok, binary} | :drop | {:error, term}. state is the immutable value from init/2; mutable state must be kept by the plugin itself (its own ETS table or process), because this is called concurrently from many processes.

  • :passive - must return {:ok, new_state}. Runs in the instance process.

handle_info(msg, state)

(optional)
@callback handle_info(msg :: term(), state :: term()) :: {:ok, new_state :: term()}

Optional message handler for passive plugins.

A passive plugin's self() is the instance process, so Process.send_after(self(), ...) from init/2 or handle_frame/3 is the supported way to schedule periodic work.

hooks()

@callback hooks() :: [direction()]

Which directions this plugin wants. Never called for others.

init(t, keyword)

@callback init(
  Xirsys.XTurn.Plugin.Allocation.t(),
  keyword()
) :: {:ok, state :: term()} | :ignore

Called once per attached allocation.

For :passive plugins this runs inside the instance process. Returning :ignore aborts attachment.

mode()

@callback mode() :: :active | :passive

Fixed for the lifetime of the module: :active or :passive.