XGW.Peer.Gather (xgw v0.1.0)

Copy Markdown View Source

Post-SDP local candidate checks and background srflx/relay gather for a Peer.

Why this sits beside XGW.Peer

After apply_descriptions/4, a full-ICE Peer may still need server-reflexive or TURN relay candidates that were not ready when the answer was sent. This module (pure helpers + Task starters, not a GenServer) verifies that answer locals match Listener gather expectations and kicks off async gather that later emits {:xgw, :local_candidate, ...} / completion events via Peer.

RFCs

  • RFC 8445 -- trickle / post-answer gather of srflx and relay locals
  • RFC 8489 -- STUN Binding for srflx
  • RFC 8656 -- TURN Allocate for relay

Summary

Functions

Merges gathered srflx into ICE and notifies the handler.

Dedup key for a local ICE candidate (foundation, component, ip, port).

Returns host candidates that do not yet have an srflx with the same foundation.

Notifies handler when post-apply gather tasks have finished.

Starts async relay gather when TURN is configured and locals uncovered.

Starts async srflx gather when STUN servers and missing hosts exist.

Ensures answer locals match Listener gather expectations (full ICE only).

Functions

apply_srflx_candidates(state, srflx)

@spec apply_srflx_candidates(map(), [XMediaLib.SDP.Candidate.t()]) :: map()

Merges gathered srflx into ICE and notifies the handler.

Caller schedules connectivity-check ticks after this returns.

candidate_key(candidate)

@spec candidate_key(XMediaLib.SDP.Candidate.t()) :: {term(), term(), term(), term()}

Dedup key for a local ICE candidate (foundation, component, ip, port).

Examples

iex> c = %XMediaLib.SDP.Candidate{
...>   foundation: "1", component_id: 1, ip: "192.0.2.1", port: 5000
...> }
iex> XGW.Peer.Gather.candidate_key(c)
{"1", 1, "192.0.2.1", 5000}

hosts_missing_srflx(locals)

@spec hosts_missing_srflx([XMediaLib.SDP.Candidate.t() | map()]) :: [
  XMediaLib.SDP.Candidate.t() | map()
]

Returns host candidates that do not yet have an srflx with the same foundation.

Used to decide whether post-apply STUN gather still has work to do.

Examples

iex> hosts = [%{type: "host", foundation: "1"}, %{type: "host", foundation: "2"}]
iex> locals = hosts ++ [%{type: "srflx", foundation: "1"}]
iex> XGW.Peer.Gather.hosts_missing_srflx(locals)
[%{type: "host", foundation: "2"}]

maybe_emit_local_candidates_complete(state)

@spec maybe_emit_local_candidates_complete(map()) :: map()

Notifies handler when post-apply gather tasks have finished.

start_post_apply_relay(state)

@spec start_post_apply_relay(map()) :: map()

Starts async relay gather when TURN is configured and locals uncovered.

start_post_apply_srflx(state)

@spec start_post_apply_srflx(map()) :: map()

Starts async srflx gather when STUN servers and missing hosts exist.

verify_local_candidates(map, config)

@spec verify_local_candidates(map(), map()) ::
  :ok | {:error, :local_candidate_mismatch}

Ensures answer locals match Listener gather expectations (full ICE only).

Returns :ok for ICE-lite or when no Listener is attached.