Add WithRenominationNominationAttribute

Allow a user to set what Attribute value is used
This commit is contained in:
Sean DuBois
2026-03-25 13:37:17 -04:00
committed by Sean DuBois
parent 1f19122667
commit fc0a368148
4 changed files with 52 additions and 3 deletions
+3
View File
@@ -363,6 +363,9 @@ func (g *ICEGatherer) renominationOptions() []ice.AgentOption {
return generator()
}),
}
if renom.attributeType != nil {
opts = append(opts, ice.WithNominationAttribute(*renom.attributeType))
}
if renom.automatic {
interval := time.Duration(0)
+17 -2
View File
@@ -2128,6 +2128,16 @@ func TestICEGatherer_RenominationOptions(t *testing.T) {
assert.NotNil(t, se.renomination.generator)
}
func TestICEGatherer_RenominationInvalidAttributeFailsAtCreateAgent(t *testing.T) {
se := SettingEngine{}
assert.NoError(t, se.SetICERenomination(WithRenominationNominationAttribute(0x0000)))
gatherer, err := NewAPI(WithSettingEngine(se)).NewICEGatherer(ICEGatherOptions{})
assert.NoError(t, err)
assert.ErrorIs(t, gatherer.createAgent(), ice.ErrInvalidNominationAttribute)
}
func TestICEGatherer_RenominationOptionsDisabled(t *testing.T) {
lim := test.TimeOut(time.Second * 10)
defer lim.Stop()
@@ -2769,6 +2779,7 @@ func makeSrflxCandidateInit(c ICECandidate) ICECandidateInit {
func buildStagedRenominationPair(
t *testing.T,
bindingHandler func(*stun.Message, ice.Candidate, ice.Candidate, *ice.CandidatePair) bool,
renominationOptions ...RenominationOption,
) (*PeerConnection, *PeerConnection, *stagedCandidateSender, *stagedCandidateSender, func()) {
t.Helper()
@@ -2807,7 +2818,11 @@ func buildStagedRenominationPair(
// prefer srflx/prflx nomination first so the test reliably observes the switch to host via renomination.
offerSE.SetSrflxAcceptanceMinWait(0)
offerSE.SetHostAcceptanceMinWait(3 * time.Second)
assert.NoError(t, offerSE.SetICERenomination(WithRenominationInterval(200*time.Millisecond)))
configuredRenominationOptions := append(
[]RenominationOption{WithRenominationInterval(200 * time.Millisecond)},
renominationOptions...,
)
assert.NoError(t, offerSE.SetICERenomination(configuredRenominationOptions...))
answerSE := SettingEngine{}
answerSE.SetNet(answerNet)
@@ -2816,7 +2831,7 @@ func buildStagedRenominationPair(
answerSE.SetICETimeouts(5*time.Second, 15*time.Second, 200*time.Millisecond)
answerSE.SetSrflxAcceptanceMinWait(0)
answerSE.SetHostAcceptanceMinWait(3 * time.Second)
assert.NoError(t, answerSE.SetICERenomination(WithRenominationInterval(200*time.Millisecond)))
assert.NoError(t, answerSE.SetICERenomination(configuredRenominationOptions...))
if bindingHandler != nil {
answerSE.SetICEBindingRequestHandler(bindingHandler)
}
+12 -1
View File
@@ -123,6 +123,7 @@ type renominationSettings struct {
generator ice.NominationValueGenerator
automatic bool
automaticInterval *time.Duration
attributeType *uint16
}
// NominationValueGenerator generates nomination values for ICE renomination.
@@ -151,9 +152,18 @@ func WithRenominationInterval(interval time.Duration) RenominationOption {
}
}
// WithRenominationNominationAttribute overrides the STUN attribute type used for ICE renomination.
// If unset, the underlying ICE agent default is used.
func WithRenominationNominationAttribute(attrType uint16) RenominationOption {
return func(cfg *renominationSettings) {
a := attrType
cfg.attributeType = &a
}
}
var errInvalidRenominationInterval = errors.New("renomination interval must be greater than zero")
// SetICERenomination configures ICE renomination using options for generator and scheduling.
// SetICERenomination configures ICE renomination using options for generator, scheduling, and attribute type.
// Manual control is not exposed yet. This always enables automatic renomination with the default
// generator unless a custom one is provided.
func (e *SettingEngine) SetICERenomination(options ...RenominationOption) error {
@@ -176,6 +186,7 @@ func (e *SettingEngine) SetICERenomination(options ...RenominationOption) error
e.renomination.generator = cfg.generator
e.renomination.automatic = true
e.renomination.automaticInterval = cfg.automaticInterval
e.renomination.attributeType = cfg.attributeType
return nil
}
+20
View File
@@ -98,11 +98,31 @@ func TestICERenomination(t *testing.T) {
assert.NotNil(t, s.renomination.generator)
})
t.Run("CustomAttribute", func(t *testing.T) {
const customAttr = uint16(0x0042)
s := SettingEngine{}
assert.NoError(t, s.SetICERenomination(WithRenominationNominationAttribute(customAttr)))
assert.True(t, s.renomination.enabled)
if assert.NotNil(t, s.renomination.attributeType) {
assert.Equal(t, customAttr, *s.renomination.attributeType)
}
})
t.Run("InvalidInterval", func(t *testing.T) {
s := SettingEngine{}
assert.ErrorIs(t, s.SetICERenomination(WithRenominationInterval(0)), errInvalidRenominationInterval)
assert.ErrorIs(t, s.SetICERenomination(WithRenominationInterval(-1*time.Second)), errInvalidRenominationInterval)
})
t.Run("InvalidAttribute", func(t *testing.T) {
s := SettingEngine{}
assert.NoError(t, s.SetICERenomination(WithRenominationNominationAttribute(0x0000)))
if assert.NotNil(t, s.renomination.attributeType) {
assert.Equal(t, uint16(0x0000), *s.renomination.attributeType)
}
})
}
func TestDetachDataChannels(t *testing.T) {