mirror of
https://github.com/netbirdio/ice.git
synced 2026-05-22 17:10:58 -07:00
Accept aggressive nomination
Add config for accept aggressive nomination, it is useful for compatible with chrome or other clients use aggressive nominate to update nominate candidate pairs.
This commit is contained in:
@@ -14,6 +14,7 @@ backkem <mail@backkem.me>
|
||||
buptczq <czq@qq.com>
|
||||
cgojin <gongjin21@hotmail.com>
|
||||
Chao Yuan <yuanchao0310@163.com>
|
||||
cnderrauber <zengjie9004@gmail.com>
|
||||
David Hamilton <davidhamiltron@gmail.com>
|
||||
David Zhao <david@davidzhao.com>
|
||||
Henry <cryptix@riseup.net>
|
||||
|
||||
@@ -133,6 +133,8 @@ type Agent struct {
|
||||
insecureSkipVerify bool
|
||||
|
||||
proxyDialer proxy.Dialer
|
||||
|
||||
acceptAggressiveNomination bool
|
||||
}
|
||||
|
||||
type task struct {
|
||||
@@ -314,6 +316,8 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
|
||||
interfaceFilter: config.InterfaceFilter,
|
||||
|
||||
insecureSkipVerify: config.InsecureSkipVerify,
|
||||
|
||||
acceptAggressiveNomination: config.AcceptAggressiveNomination,
|
||||
}
|
||||
|
||||
a.tcpMux = config.TCPMux
|
||||
|
||||
@@ -159,6 +159,9 @@ type AgentConfig struct {
|
||||
// Proxy Dialer is a dialer that should be implemented by the user based on golang.org/x/net/proxy
|
||||
// dial interface in order to support corporate proxies
|
||||
ProxyDialer proxy.Dialer
|
||||
|
||||
// Accept aggressive nomination in RFC 5245 for compatible with chrome and other browsers
|
||||
AcceptAggressiveNomination bool
|
||||
}
|
||||
|
||||
// initWithDefaults populates an agent and falls back to defaults if fields are unset
|
||||
|
||||
+124
@@ -1,3 +1,4 @@
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package ice
|
||||
@@ -1763,3 +1764,126 @@ func TestGetSelectedCandidatePair(t *testing.T) {
|
||||
assert.NoError(t, aAgent.Close())
|
||||
assert.NoError(t, bAgent.Close())
|
||||
}
|
||||
|
||||
func TestAcceptAggressiveNomination(t *testing.T) {
|
||||
report := test.CheckRoutines(t)
|
||||
defer report()
|
||||
|
||||
lim := test.TimeOut(time.Second * 30)
|
||||
defer lim.Stop()
|
||||
|
||||
// Create a network with two interfaces
|
||||
wan, err := vnet.NewRouter(&vnet.RouterConfig{
|
||||
CIDR: "0.0.0.0/0",
|
||||
LoggerFactory: logging.NewDefaultLoggerFactory(),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
net0 := vnet.NewNet(&vnet.NetConfig{
|
||||
StaticIPs: []string{"192.168.0.1"},
|
||||
})
|
||||
assert.NoError(t, wan.AddNet(net0))
|
||||
|
||||
net1 := vnet.NewNet(&vnet.NetConfig{
|
||||
StaticIPs: []string{"192.168.0.2", "192.168.0.3", "192.168.0.4"},
|
||||
})
|
||||
assert.NoError(t, wan.AddNet(net1))
|
||||
|
||||
assert.NoError(t, wan.Start())
|
||||
|
||||
aNotifier, aConnected := onConnected()
|
||||
bNotifier, bConnected := onConnected()
|
||||
|
||||
KeepaliveInterval := time.Hour
|
||||
cfg0 := &AgentConfig{
|
||||
NetworkTypes: supportedNetworkTypes(),
|
||||
MulticastDNSMode: MulticastDNSModeDisabled,
|
||||
Net: net0,
|
||||
|
||||
KeepaliveInterval: &KeepaliveInterval,
|
||||
CheckInterval: &KeepaliveInterval,
|
||||
AcceptAggressiveNomination: true,
|
||||
}
|
||||
|
||||
var aAgent, bAgent *Agent
|
||||
aAgent, err = NewAgent(cfg0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, aAgent.OnConnectionStateChange(aNotifier))
|
||||
|
||||
cfg1 := &AgentConfig{
|
||||
NetworkTypes: supportedNetworkTypes(),
|
||||
MulticastDNSMode: MulticastDNSModeDisabled,
|
||||
Net: net1,
|
||||
KeepaliveInterval: &KeepaliveInterval,
|
||||
CheckInterval: &KeepaliveInterval,
|
||||
}
|
||||
|
||||
bAgent, err = NewAgent(cfg1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, bAgent.OnConnectionStateChange(bNotifier))
|
||||
|
||||
aConn, bConn := connect(aAgent, bAgent)
|
||||
|
||||
// Ensure pair selected
|
||||
// Note: this assumes ConnectionStateConnected is thrown after selecting the final pair
|
||||
<-aConnected
|
||||
<-bConnected
|
||||
|
||||
// Send new USE-CANDIDATE message with higher priority to update the selected pair
|
||||
buildMsg := func(class stun.MessageClass, username, key string, priority uint32) *stun.Message {
|
||||
msg, err1 := stun.Build(stun.NewType(stun.MethodBinding, class), stun.TransactionID,
|
||||
stun.NewUsername(username),
|
||||
stun.NewShortTermIntegrity(key),
|
||||
UseCandidate(),
|
||||
PriorityAttr(priority),
|
||||
stun.Fingerprint,
|
||||
)
|
||||
if err1 != nil {
|
||||
t.Fatal(err1)
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
selectedCh := make(chan Candidate, 1)
|
||||
var expectNewSelectedCandidate Candidate
|
||||
err = aAgent.OnSelectedCandidatePairChange(func(_, remote Candidate) {
|
||||
selectedCh <- remote
|
||||
})
|
||||
require.NoError(t, err)
|
||||
var bcandidates []Candidate
|
||||
bcandidates, err = bAgent.GetLocalCandidates()
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, c := range bcandidates {
|
||||
if c != bAgent.getSelectedPair().Local {
|
||||
if expectNewSelectedCandidate == nil {
|
||||
incr_priority:
|
||||
for _, candidates := range aAgent.remoteCandidates {
|
||||
for _, candidate := range candidates {
|
||||
if candidate.Equal(c) {
|
||||
candidate.(*CandidateHost).priorityOverride += 1000
|
||||
break incr_priority
|
||||
}
|
||||
}
|
||||
}
|
||||
expectNewSelectedCandidate = c
|
||||
}
|
||||
_, err = c.writeTo(buildMsg(stun.ClassRequest, aAgent.localUfrag+":"+aAgent.remoteUfrag, aAgent.localPwd, c.Priority()).Raw, bAgent.getSelectedPair().Remote)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
select {
|
||||
case selected := <-selectedCh:
|
||||
assert.True(t, selected.Equal(expectNewSelectedCandidate))
|
||||
default:
|
||||
t.Fatal("No selected candidate pair")
|
||||
}
|
||||
|
||||
assert.NoError(t, wan.Stop())
|
||||
if !closePipe(t, aConn, bConn) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -252,8 +252,11 @@ func (s *controlledSelector) HandleBindingRequest(m *stun.Message, local, remote
|
||||
// previously sent by this pair produced a successful response and
|
||||
// generated a valid pair (Section 7.2.5.3.2). The agent sets the
|
||||
// nominated flag value of the valid pair to true.
|
||||
if selectedPair := s.agent.getSelectedPair(); selectedPair == nil {
|
||||
if selectedPair := s.agent.getSelectedPair(); selectedPair == nil ||
|
||||
(s.agent.acceptAggressiveNomination && selectedPair.priority() < p.priority()) {
|
||||
s.agent.setSelectedPair(p)
|
||||
} else if selectedPair != p {
|
||||
s.log.Tracef("ignore nominate new pair %s, already nominated pair %s", p, selectedPair)
|
||||
}
|
||||
} else {
|
||||
// If the received Binding request triggered a new check to be
|
||||
|
||||
Reference in New Issue
Block a user