XGW.ICE.Full (xgw v0.1.0)

Copy Markdown View Source

Full ICE agent: gather candidates, run the checklist, nominate a pair.

When to use full ICE

ICE-lite only answers inbound STUN checks (typical for a public server with a known address). Full ICE also gathers local candidates, forms pairs, and sends outbound connectivity checks -- required when the gateway sits behind NAT or needs TURN relay paths itself.

Phase transitions:

:gathering -> :checking -> :connected

Outbound and inbound STUN checks, nomination (USE-CANDIDATE), and trickle candidate merges all live here. Pure helpers stay in XGW.ICE / XGW.ICE.Checklist; this module owns agent state updates used by XGW.Peer.

RFCs

  • RFC 8445 -- full ICE agent (gather, checklist, checks, nomination, phases)
  • RFC 8489 -- STUN Binding for connectivity checks
  • RFC 7675 -- consent freshness after nomination

Summary

Types

Remote UDP endpoint {ip, port}.

Result of handling inbound STUN while checking or connected.

t()

Full ICE agent state.

Functions

Merges one local candidate (host, srflx, or relay trickle) into the agent.

Adds a trickle remote candidate or records end-of-candidates.

Checklist tick interval in milliseconds (Ta).

Returns checklist inputs for pair formation.

Rebuilds the checklist after new local candidates arrive (srflx/relay trickle).

Builds full ICE state from XGW.Descriptions config after negotiation.

Handles one STUN datagram (inbound checks and outbound responses).

Resets checklist state for ICE restart (remote ufrag/pwd supplied by caller).

Marks ICE processing complete after nomination (:connected -> :completed).

Builds an empty full ICE agent (before apply_descriptions).

Returns the ICE phase.

Returns true when at least one local and one remote candidate exist.

Seeds local candidates from the local answer SDP.

Seeds remote candidates from the initial offer SDP.

Builds the checklist and moves phase to :checking.

Processes one checklist tick; may return an outbound STUN check to send.

Types

from()

@type from() :: XGW.ICE.endpoint()

Remote UDP endpoint {ip, port}.

stun_result()

@type stun_result() ::
  {:ignore, t()}
  | {:reply, binary(), t()}
  | {:send, binary(), from(), t()}
  | {:connected, binary(), t(), from()}
  | {:consent, t()}

Result of handling inbound STUN while checking or connected.

Includes consent refresh (:consent) and nomination (:connected).

t()

@type t() :: %{
  phase: XGW.ICE.ice_phase(),
  role: XGW.ICE.role(),
  tiebreaker: binary(),
  ice_ufrag: String.t() | nil,
  ice_pwd: String.t() | nil,
  remote_ice_ufrag: String.t() | nil,
  remote_ice_pwd: String.t() | nil,
  bundle_mids: [String.t()],
  local_candidates: [XMediaLib.SDP.Candidate.t()],
  remote_candidates: [XMediaLib.SDP.Candidate.t()],
  remote_candidates_eoc?: boolean(),
  checklist: [XGW.ICE.Checklist.pair()],
  nominated_pair: XGW.ICE.Checklist.pair() | nil,
  selected: from() | nil,
  pending_triggered: XGW.ICE.Checklist.pair() | nil,
  last_consent_at: integer() | nil
}

Full ICE agent state.

Functions

add_local_candidate(full, cand)

@spec add_local_candidate(t(), XMediaLib.SDP.Candidate.t()) :: {:ok, t()}

Merges one local candidate (host, srflx, or relay trickle) into the agent.

add_remote_candidate(full, cand)

@spec add_remote_candidate(t(), map() | XMediaLib.SDP.Candidate.t()) ::
  {:ok, t()} | {:error, term()}

Adds a trickle remote candidate or records end-of-candidates.

check_ta_ms()

@spec check_ta_ms() :: pos_integer()

Checklist tick interval in milliseconds (Ta).

checklist_inputs(map)

@spec checklist_inputs(t()) :: %{
  local: [XMediaLib.SDP.Candidate.t()],
  remote: [XMediaLib.SDP.Candidate.t()]
}

Returns checklist inputs for pair formation.

extend_locals(full, new_locals)

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

Rebuilds the checklist after new local candidates arrive (srflx/relay trickle).

from_config(config)

@spec from_config(map()) :: {:ok, t()} | {:error, :unsupported_setup}

Builds full ICE state from XGW.Descriptions config after negotiation.

handle_stun(data, from, full, opts \\ [])

@spec handle_stun(binary(), from(), t(), keyword()) :: stun_result()

Handles one STUN datagram (inbound checks and outbound responses).

Options:

  • :transport - :udp (default) or :tcp (ICE-TCP path; peer-reflexive remotes inherit this so checklist pairs can form)

ice_restart(full)

@spec ice_restart(t()) :: t()

Resets checklist state for ICE restart (remote ufrag/pwd supplied by caller).

mark_completed(full)

@spec mark_completed(t()) :: t()

Marks ICE processing complete after nomination (:connected -> :completed).

new(opts \\ [])

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

Builds an empty full ICE agent (before apply_descriptions).

phase(map)

@spec phase(t()) :: XGW.ICE.ice_phase()

Returns the ICE phase.

ready_for_checks?(full)

@spec ready_for_checks?(t()) :: boolean()

Returns true when at least one local and one remote candidate exist.

seed_local_candidates(full, candidates)

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

Seeds local candidates from the local answer SDP.

seed_remote_candidates(full, candidates)

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

Seeds remote candidates from the initial offer SDP.

start_checking(full)

@spec start_checking(t()) :: t()

Builds the checklist and moves phase to :checking.

tick(full, now_ms)

@spec tick(t(), integer()) ::
  {:noop, t()} | {:send, binary(), from(), t(), non_neg_integer()}

Processes one checklist tick; may return an outbound STUN check to send.