Files
ice/agent_options.go
2025-08-25 11:44:35 -04:00

155 lines
5.0 KiB
Go

// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
package ice
import (
"sync/atomic"
"github.com/pion/stun/v3"
)
// AgentOption represents a function that can be used to configure an Agent.
type AgentOption func(*Agent) error
// NominationValueGenerator is a function that generates nomination values for renomination.
type NominationValueGenerator func() uint32
// DefaultNominationValueGenerator returns a generator that starts at 1 and increments for each call.
// This provides a simple, monotonically increasing sequence suitable for renomination.
func DefaultNominationValueGenerator() NominationValueGenerator {
var counter atomic.Uint32
return func() uint32 {
return counter.Add(1)
}
}
// WithRenomination enables ICE renomination as described in draft-thatcher-ice-renomination-01.
// When enabled, the controlling agent can renominate candidate pairs multiple times
// and the controlled agent follows "last nomination wins" rule.
//
// The generator parameter specifies how nomination values are generated.
// Use DefaultNominationValueGenerator() for a simple incrementing counter,
// or provide a custom generator for more complex scenarios.
//
// Example:
//
// agent, err := NewAgentWithOptions(config, WithRenomination(DefaultNominationValueGenerator()))
func WithRenomination(generator NominationValueGenerator) AgentOption {
return func(a *Agent) error {
if generator == nil {
return ErrInvalidNominationValueGenerator
}
a.enableRenomination = true
a.nominationValueGenerator = generator
return nil
}
}
// WithNominationAttribute sets the STUN attribute type to use for ICE renomination.
// The default value is 0x0030. This can be configured until the attribute is officially
// assigned by IANA for draft-thatcher-ice-renomination.
//
// This option returns an error if the provided attribute type is invalid.
// Currently, validation ensures the attribute is not 0x0000 (reserved).
// Additional validation may be added in the future.
func WithNominationAttribute(attrType uint16) AgentOption {
return func(a *Agent) error {
// Basic validation: ensure it's not the reserved 0x0000
if attrType == 0x0000 {
return ErrInvalidNominationAttribute
}
a.nominationAttribute = stun.AttrType(attrType)
return nil
}
}
// WithIncludeLoopback includes loopback addresses in the candidate list.
// By default, loopback addresses are excluded.
//
// Example:
//
// agent, err := NewAgentWithOptions(WithIncludeLoopback())
func WithIncludeLoopback() AgentOption {
return func(a *Agent) error {
a.includeLoopback = true
return nil
}
}
// WithTCPPriorityOffset sets a number which is subtracted from the default (UDP) candidate type preference
// for host, srflx and prfx candidate types. It helps to configure relative preference of UDP candidates
// against TCP ones. Relay candidates for TCP and UDP are always 0 and not affected by this setting.
// When not set, defaultTCPPriorityOffset (27) is used.
//
// Example:
//
// agent, err := NewAgentWithOptions(WithTCPPriorityOffset(50))
func WithTCPPriorityOffset(offset uint16) AgentOption {
return func(a *Agent) error {
a.tcpPriorityOffset = offset
return nil
}
}
// WithDisableActiveTCP disables Active TCP candidates.
// When TCP is enabled, Active TCP candidates will be created when a new passive TCP remote candidate is added
// unless this option is used.
//
// Example:
//
// agent, err := NewAgentWithOptions(WithDisableActiveTCP())
func WithDisableActiveTCP() AgentOption {
return func(a *Agent) error {
a.disableActiveTCP = true
return nil
}
}
// WithBindingRequestHandler sets a handler to allow applications to perform logic on incoming STUN Binding Requests.
// This was implemented to allow users to:
// - Log incoming Binding Requests for debugging
// - Implement draft-thatcher-ice-renomination
// - Implement custom CandidatePair switching logic
//
// Example:
//
// handler := func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool {
// log.Printf("Binding request from %s to %s", remote.Address(), local.Address())
// return true // Accept the request
// }
// agent, err := NewAgentWithOptions(WithBindingRequestHandler(handler))
func WithBindingRequestHandler(
handler func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool,
) AgentOption {
return func(a *Agent) error {
a.userBindingRequestHandler = handler
return nil
}
}
// WithEnableUseCandidateCheckPriority enables checking for equal or higher priority when
// switching selected candidate pair if the peer requests USE-CANDIDATE and agent is a lite agent.
// This is disabled by default, i.e. when peer requests USE-CANDIDATE, the selected pair will be
// switched to that irrespective of relative priority between current selected pair
// and priority of the pair being switched to.
//
// Example:
//
// agent, err := NewAgentWithOptions(WithEnableUseCandidateCheckPriority())
func WithEnableUseCandidateCheckPriority() AgentOption {
return func(a *Agent) error {
a.enableUseCandidateCheckPriority = true
return nil
}
}