Move localInterfaces and listenUDPInPortRange

Move more code out of the agent that doesn't actually require any state
from the ICE Agent.

Relates to #118
This commit is contained in:
Sean DuBois
2020-02-23 22:05:13 -08:00
parent 11318ea39f
commit 9ca33c2380
4 changed files with 120 additions and 120 deletions
+4 -106
View File
@@ -2,12 +2,10 @@ package ice
import (
"fmt"
"math/rand"
"net"
"sync"
"time"
"github.com/pion/transport/vnet"
"github.com/pion/turn/v2"
)
@@ -15,106 +13,6 @@ const (
stunGatherTimeout = time.Second * 5
)
func (a *Agent) localInterfaces(networkTypes []NetworkType) ([]net.IP, error) {
ips := []net.IP{}
ifaces, err := a.net.Interfaces()
if err != nil {
return ips, err
}
var IPv4Requested, IPv6Requested bool
for _, typ := range networkTypes {
if typ.IsIPv4() {
IPv4Requested = true
}
if typ.IsIPv6() {
IPv6Requested = true
}
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
if a.interfaceFilter != nil && !a.interfaceFilter(iface.Name) {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch addr := addr.(type) {
case *net.IPNet:
ip = addr.IP
case *net.IPAddr:
ip = addr.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
if ipv4 := ip.To4(); ipv4 == nil {
if !IPv6Requested {
continue
} else if !isSupportedIPv6(ip) {
continue
}
} else if !IPv4Requested {
continue
}
ips = append(ips, ip)
}
}
return ips, nil
}
func (a *Agent) listenUDP(portMax, portMin int, network string, laddr *net.UDPAddr) (vnet.UDPPacketConn, error) {
if (laddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
return a.net.ListenUDP(network, laddr)
}
var i, j int
i = portMin
if i == 0 {
i = 1
}
j = portMax
if j == 0 {
j = 0xFFFF
}
if i > j {
return nil, ErrPort
}
portStart := rand.Intn(j-i+1) + i
portCurrent := portStart
for {
laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent}
c, e := a.net.ListenUDP(network, laddr)
if e == nil {
return c, e
}
a.log.Debugf("failed to listen %s: %v", laddr.String(), e)
portCurrent++
if portCurrent > j {
portCurrent = i
}
if portCurrent == portStart {
break
}
}
return nil, ErrPort
}
// GatherCandidates initiates the trickle based gathering process.
func (a *Agent) GatherCandidates() error {
gatherErrChan := make(chan error, 1)
@@ -183,7 +81,7 @@ func (a *Agent) gatherCandidatesLocal(networkTypes []NetworkType) {
var wg sync.WaitGroup
defer wg.Wait()
localIPs, err := a.localInterfaces(networkTypes)
localIPs, err := localInterfaces(a.net, a.interfaceFilter, networkTypes)
if err != nil {
a.log.Warnf("failed to iterate local interfaces, host candidates will not be gathered %s", err)
return
@@ -203,7 +101,7 @@ func (a *Agent) gatherCandidatesLocal(networkTypes []NetworkType) {
for _, network := range supportedNetworks {
go func(network string, ip, mappedIP net.IP) {
defer wg.Done()
conn, err := a.listenUDP(int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: ip, Port: 0})
conn, err := listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
a.log.Warnf("could not listen %s %s\n", network, ip)
return
@@ -274,7 +172,7 @@ func (a *Agent) gatherCandidatesSrflx(urls []*URL, networkTypes []NetworkType) {
continue
}
conn, err := a.listenUDP(int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
conn, err := listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
if err != nil {
a.log.Warnf("Failed to listen for %s: %v\n", serverAddr.String(), err)
continue
@@ -318,7 +216,7 @@ func (a *Agent) gatherCandidatesSrflx(urls []*URL, networkTypes []NetworkType) {
}
}
} else if a.extIPMapper != nil && a.extIPMapper.candidateType == CandidateTypeServerReflexive {
conn, err := a.listenUDP(int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
conn, err := listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
if err != nil {
a.log.Warnf("Failed to listen %s: %v\n", network, err)
continue
+6 -6
View File
@@ -16,20 +16,20 @@ func TestListenUDP(t *testing.T) {
a, err := NewAgent(&AgentConfig{})
assert.NoError(t, err)
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
assert.NotEqual(t, len(localIPs), 0, "localInterfaces found no interfaces, unable to test")
assert.NoError(t, err)
ip := localIPs[0]
conn, err := a.listenUDP(0, 0, udp, &net.UDPAddr{IP: ip, Port: 0})
conn, err := listenUDPInPortRange(a.net, a.log, 0, 0, udp, &net.UDPAddr{IP: ip, Port: 0})
assert.NoError(t, err, "listenUDP error with no port restriction")
assert.NotNil(t, conn, "listenUDP error with no port restriction return a nil conn")
_, err = a.listenUDP(4999, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
_, err = listenUDPInPortRange(a.net, a.log, 4999, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
assert.Equal(t, err, ErrPort, "listenUDP with invalid port range did not return ErrPort")
conn, err = a.listenUDP(5000, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
conn, err = listenUDPInPortRange(a.net, a.log, 5000, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
assert.NoError(t, err, "listenUDP error with no port restriction")
assert.NotNil(t, conn, "listenUDP error with no port restriction return a nil conn")
@@ -43,7 +43,7 @@ func TestListenUDP(t *testing.T) {
result := make([]int, 0, total)
portRange := make([]int, 0, total)
for i := 0; i < total; i++ {
conn, err = a.listenUDP(portMax, portMin, udp, &net.UDPAddr{IP: ip, Port: 0})
conn, err = listenUDPInPortRange(a.net, a.log, portMax, portMin, udp, &net.UDPAddr{IP: ip, Port: 0})
assert.NoError(t, err, "listenUDP error with no port restriction")
assert.NotNil(t, conn, "listenUDP error with no port restriction return a nil conn")
@@ -65,7 +65,7 @@ func TestListenUDP(t *testing.T) {
if !reflect.DeepEqual(result, portRange) {
t.Fatalf("listenUDP with port restriction [%d, %d], got:%v, want:%v", portMin, portMax, result, portRange)
}
_, err = a.listenUDP(portMax, portMin, udp, &net.UDPAddr{IP: ip, Port: 0})
_, err = listenUDPInPortRange(a.net, a.log, portMax, portMin, udp, &net.UDPAddr{IP: ip, Port: 0})
assert.Equal(t, err, ErrPort, "listenUDP with port restriction [%d, %d], did not return ErrPort", portMin, portMax)
assert.NoError(t, a.Close())
+8 -8
View File
@@ -26,7 +26,7 @@ func TestVNetGather(t *testing.T) {
})
assert.NoError(t, err)
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if len(localIPs) > 0 {
t.Fatal("should return no local IP")
} else if err != nil {
@@ -66,7 +66,7 @@ func TestVNetGather(t *testing.T) {
})
assert.NoError(t, err)
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if len(localIPs) == 0 {
t.Fatal("should have one local IP")
} else if err != nil {
@@ -109,7 +109,7 @@ func TestVNetGather(t *testing.T) {
t.Fatalf("Failed to create agent: %s", err)
}
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if len(localIPs) == 0 {
t.Fatal("localInterfaces found no interfaces, unable to test")
} else if err != nil {
@@ -118,7 +118,7 @@ func TestVNetGather(t *testing.T) {
ip := localIPs[0]
conn, err := a.listenUDP(0, 0, udp, &net.UDPAddr{IP: ip, Port: 0})
conn, err := listenUDPInPortRange(a.net, a.log, 0, 0, udp, &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
t.Fatalf("listenUDP error with no port restriction %v", err)
} else if conn == nil {
@@ -129,12 +129,12 @@ func TestVNetGather(t *testing.T) {
t.Fatalf("failed to close conn")
}
_, err = a.listenUDP(4999, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
_, err = listenUDPInPortRange(a.net, a.log, 4999, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
if err != ErrPort {
t.Fatal("listenUDP with invalid port range did not return ErrPort")
}
conn, err = a.listenUDP(5000, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
conn, err = listenUDPInPortRange(a.net, a.log, 5000, 5000, udp, &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
t.Fatalf("listenUDP error with no port restriction %v", err)
} else if conn == nil {
@@ -384,7 +384,7 @@ func TestVNetGatherWithInterfaceFilter(t *testing.T) {
})
assert.NoError(t, err)
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if err != nil {
t.Fatal(err)
} else if len(localIPs) != 0 {
@@ -404,7 +404,7 @@ func TestVNetGatherWithInterfaceFilter(t *testing.T) {
})
assert.NoError(t, err)
localIPs, err := a.localInterfaces([]NetworkType{NetworkTypeUDP4})
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if err != nil {
t.Fatal(err)
} else if len(localIPs) == 0 {
+102
View File
@@ -7,7 +7,9 @@ import (
"sync/atomic"
"time"
"github.com/pion/logging"
"github.com/pion/stun"
"github.com/pion/transport/vnet"
)
type atomicError struct{ v atomic.Value }
@@ -144,3 +146,103 @@ func stunRequest(read func([]byte) (int, error), write func([]byte) (int, error)
}
return res, nil
}
func localInterfaces(vnet *vnet.Net, interfaceFilter func(string) bool, networkTypes []NetworkType) ([]net.IP, error) {
ips := []net.IP{}
ifaces, err := vnet.Interfaces()
if err != nil {
return ips, err
}
var IPv4Requested, IPv6Requested bool
for _, typ := range networkTypes {
if typ.IsIPv4() {
IPv4Requested = true
}
if typ.IsIPv6() {
IPv6Requested = true
}
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
if interfaceFilter != nil && !interfaceFilter(iface.Name) {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch addr := addr.(type) {
case *net.IPNet:
ip = addr.IP
case *net.IPAddr:
ip = addr.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
if ipv4 := ip.To4(); ipv4 == nil {
if !IPv6Requested {
continue
} else if !isSupportedIPv6(ip) {
continue
}
} else if !IPv4Requested {
continue
}
ips = append(ips, ip)
}
}
return ips, nil
}
func listenUDPInPortRange(vnet *vnet.Net, log logging.LeveledLogger, portMax, portMin int, network string, laddr *net.UDPAddr) (vnet.UDPPacketConn, error) {
if (laddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
return vnet.ListenUDP(network, laddr)
}
var i, j int
i = portMin
if i == 0 {
i = 1
}
j = portMax
if j == 0 {
j = 0xFFFF
}
if i > j {
return nil, ErrPort
}
portStart := rand.Intn(j-i+1) + i
portCurrent := portStart
for {
laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent}
c, e := vnet.ListenUDP(network, laddr)
if e == nil {
return c, e
}
log.Debugf("failed to listen %s: %v", laddr.String(), e)
portCurrent++
if portCurrent > j {
portCurrent = i
}
if portCurrent == portStart {
break
}
}
return nil, ErrPort
}