From f07b6d16adeaff82b60770c8adc1a2d41b6c09c0 Mon Sep 17 00:00:00 2001 From: San9H0 Date: Thu, 15 Dec 2022 20:41:44 +0900 Subject: [PATCH] Add RemoteCandidateCache for better performance Check sourceAddress from first packet validation of STUNTraffic. If validation is true, store it in the cache. Use cache for performance. --- addr.go | 22 +++++++++++++++++++++- agent.go | 9 ++++----- candidate_base.go | 27 ++++++++++++++++++++++++--- candidate_host.go | 17 +++++++++-------- candidate_peer_reflexive.go | 1 + candidate_relay.go | 1 + candidate_server_reflexive.go | 1 + 7 files changed, 61 insertions(+), 17 deletions(-) diff --git a/addr.go b/addr.go index 1a7f477..1d70025 100644 --- a/addr.go +++ b/addr.go @@ -3,7 +3,9 @@ package ice -import "net" +import ( + "net" +) func parseMulticastAnswerAddr(in net.Addr) (net.IP, bool) { switch addr := in.(type) { @@ -49,3 +51,21 @@ func addrEqual(a, b net.Addr) bool { return aType == bType && aIP.Equal(bIP) && aPort == bPort } + +// AddrPort is an IP and a port number. +type AddrPort [18]byte + +func toAddrPort(addr net.Addr) AddrPort { + var ap AddrPort + switch addr := addr.(type) { + case *net.UDPAddr: + copy(ap[:16], addr.IP.To16()) + ap[16] = uint8(addr.Port >> 8) + ap[17] = uint8(addr.Port) + case *net.TCPAddr: + copy(ap[:16], addr.IP.To16()) + ap[16] = uint8(addr.Port >> 8) + ap[17] = uint8(addr.Port) + } + return ap +} diff --git a/agent.go b/agent.go index 094d7fd..0a3319d 100644 --- a/agent.go +++ b/agent.go @@ -1138,19 +1138,18 @@ func (a *Agent) handleInbound(m *stun.Message, local Candidate, remote net.Addr) // validateNonSTUNTraffic processes non STUN traffic from a remote candidate, // and returns true if it is an actual remote candidate -func (a *Agent) validateNonSTUNTraffic(local Candidate, remote net.Addr) bool { - var isValidCandidate uint64 +func (a *Agent) validateNonSTUNTraffic(local Candidate, remote net.Addr) (Candidate, bool) { + var remoteCandidate Candidate if err := a.run(local.context(), func(ctx context.Context, agent *Agent) { - remoteCandidate := a.findRemoteCandidate(local.NetworkType(), remote) + remoteCandidate = a.findRemoteCandidate(local.NetworkType(), remote) if remoteCandidate != nil { remoteCandidate.seen(false) - atomic.AddUint64(&isValidCandidate, 1) } }); err != nil { a.log.Warnf("failed to validate remote candidate: %v", err) } - return atomic.LoadUint64(&isValidCandidate) == 1 + return remoteCandidate, remoteCandidate != nil } // GetSelectedCandidatePair returns the selected pair or nil if there is none diff --git a/candidate_base.go b/candidate_base.go index e455185..8e551d8 100644 --- a/candidate_base.go +++ b/candidate_base.go @@ -41,6 +41,8 @@ type candidateBase struct { foundationOverride string priorityOverride uint32 + + remoteCandidateCaches map[AddrPort]Candidate } // Done implements context.Context @@ -234,6 +236,21 @@ func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) { } } +func (c *candidateBase) validateSTUNTrafficCache(addr net.Addr) bool { + if candidate, ok := c.remoteCandidateCaches[toAddrPort(addr)]; ok { + candidate.seen(false) + return true + } + return false +} + +func (c *candidateBase) addRemoteCandidateCache(candidate Candidate, srcAddr net.Addr) { + if c.validateSTUNTrafficCache(srcAddr) { + return + } + c.remoteCandidateCaches[toAddrPort(srcAddr)] = candidate +} + func (c *candidateBase) handleInboundPacket(buf []byte, srcAddr net.Addr) { a := c.agent() @@ -259,9 +276,13 @@ func (c *candidateBase) handleInboundPacket(buf []byte, srcAddr net.Addr) { return } - if !a.validateNonSTUNTraffic(c, srcAddr) { //nolint:contextcheck - a.log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr()) - return + if !c.validateSTUNTrafficCache(srcAddr) { + remoteCandidate, valid := a.validateNonSTUNTraffic(c, srcAddr) //nolint:contextcheck + if !valid { + a.log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr()) + return + } + c.addRemoteCandidateCache(remoteCandidate, srcAddr) } // Note: This will return packetio.ErrFull if the buffer ever manages to fill up. diff --git a/candidate_host.go b/candidate_host.go index 3774cc4..5d207dd 100644 --- a/candidate_host.go +++ b/candidate_host.go @@ -37,14 +37,15 @@ func NewCandidateHost(config *CandidateHostConfig) (*CandidateHost, error) { c := &CandidateHost{ candidateBase: candidateBase{ - id: candidateID, - address: config.Address, - candidateType: CandidateTypeHost, - component: config.Component, - port: config.Port, - tcpType: config.TCPType, - foundationOverride: config.Foundation, - priorityOverride: config.Priority, + id: candidateID, + address: config.Address, + candidateType: CandidateTypeHost, + component: config.Component, + port: config.Port, + tcpType: config.TCPType, + foundationOverride: config.Foundation, + priorityOverride: config.Priority, + remoteCandidateCaches: map[AddrPort]Candidate{}, }, network: config.Network, } diff --git a/candidate_peer_reflexive.go b/candidate_peer_reflexive.go index c09bf8b..f019ec6 100644 --- a/candidate_peer_reflexive.go +++ b/candidate_peer_reflexive.go @@ -59,6 +59,7 @@ func NewCandidatePeerReflexive(config *CandidatePeerReflexiveConfig) (*Candidate Address: config.RelAddr, Port: config.RelPort, }, + remoteCandidateCaches: map[AddrPort]Candidate{}, }, }, nil } diff --git a/candidate_relay.go b/candidate_relay.go index 9339947..449d077 100644 --- a/candidate_relay.go +++ b/candidate_relay.go @@ -63,6 +63,7 @@ func NewCandidateRelay(config *CandidateRelayConfig) (*CandidateRelay, error) { Address: config.RelAddr, Port: config.RelPort, }, + remoteCandidateCaches: map[AddrPort]Candidate{}, }, relayProtocol: config.RelayProtocol, onClose: config.OnClose, diff --git a/candidate_server_reflexive.go b/candidate_server_reflexive.go index 8616fac..3a8ac0f 100644 --- a/candidate_server_reflexive.go +++ b/candidate_server_reflexive.go @@ -55,6 +55,7 @@ func NewCandidateServerReflexive(config *CandidateServerReflexiveConfig) (*Candi Address: config.RelAddr, Port: config.RelPort, }, + remoteCandidateCaches: map[AddrPort]Candidate{}, }, }, nil }