don't spam calls to net.Interfaces and net.Interface.Addrs (hopefully)

This commit is contained in:
Arceliar 2020-05-24 15:24:39 -05:00
parent 1e471e3712
commit 98816f34b2

View File

@ -21,14 +21,20 @@ import (
// automatically. // automatically.
type Multicast struct { type Multicast struct {
phony.Inbox phony.Inbox
core *yggdrasil.Core core *yggdrasil.Core
config *config.NodeState config *config.NodeState
log *log.Logger log *log.Logger
sock *ipv6.PacketConn sock *ipv6.PacketConn
groupAddr string groupAddr string
listeners map[string]*listenerInfo listeners map[string]*listenerInfo
listenPort uint16 listenPort uint16
isOpen bool isOpen bool
_interfaces map[string]interfaceInfo
}
type interfaceInfo struct {
iface net.Interface
addrs []net.Addr
} }
type listenerInfo struct { type listenerInfo struct {
@ -43,6 +49,7 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log
m.config = state m.config = state
m.log = log m.log = log
m.listeners = make(map[string]*listenerInfo) m.listeners = make(map[string]*listenerInfo)
m._interfaces = make(map[string]interfaceInfo)
current := m.config.GetCurrent() current := m.config.GetCurrent()
m.listenPort = current.LinkLocalTCPPort m.listenPort = current.LinkLocalTCPPort
m.groupAddr = "[ff02::114]:9001" m.groupAddr = "[ff02::114]:9001"
@ -148,10 +155,35 @@ func (m *Multicast) _updateConfig(config *config.NodeConfig) {
m.log.Debugln("Reloaded multicast configuration successfully") m.log.Debugln("Reloaded multicast configuration successfully")
} }
// GetInterfaces returns the currently known/enabled multicast interfaces. It is func (m *Multicast) _updateInterfaces() {
// expected that UpdateInterfaces has been called at least once before calling interfaces := make(map[string]interfaceInfo)
// this method. intfs := m.getAllowedInterfaces()
for _, intf := range intfs {
addrs, err := intf.Addrs()
if err != nil {
m.log.Warnf("Failed up get addresses for interface %s: %s", intf.Name, err)
continue
}
interfaces[intf.Name] = interfaceInfo{
iface: intf,
addrs: addrs,
}
}
m._interfaces = interfaces
}
func (m *Multicast) Interfaces() map[string]net.Interface { func (m *Multicast) Interfaces() map[string]net.Interface {
interfaces := make(map[string]net.Interface)
phony.Block(m, func() {
for _, info := range m._interfaces {
interfaces[info.iface.Name] = info.iface
}
})
return interfaces
}
// getAllowedInterfaces returns the currently known/enabled multicast interfaces.
func (m *Multicast) getAllowedInterfaces() map[string]net.Interface {
interfaces := make(map[string]net.Interface) interfaces := make(map[string]net.Interface)
// Get interface expressions from config // Get interface expressions from config
current := m.config.GetCurrent() current := m.config.GetCurrent()
@ -194,6 +226,7 @@ func (m *Multicast) _announce() {
if !m.isOpen { if !m.isOpen {
return return
} }
m._updateInterfaces()
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil { if err != nil {
panic(err) panic(err)
@ -202,7 +235,6 @@ func (m *Multicast) _announce() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
interfaces := m.Interfaces()
// There might be interfaces that we configured listeners for but are no // There might be interfaces that we configured listeners for but are no
// longer up - if that's the case then we should stop the listeners // longer up - if that's the case then we should stop the listeners
for name, info := range m.listeners { for name, info := range m.listeners {
@ -214,7 +246,7 @@ func (m *Multicast) _announce() {
} }
// If the interface is no longer visible on the system then stop the // If the interface is no longer visible on the system then stop the
// listener, as another one will be started further down // listener, as another one will be started further down
if _, ok := interfaces[name]; !ok { if _, ok := m._interfaces[name]; !ok {
stop() stop()
continue continue
} }
@ -251,13 +283,9 @@ func (m *Multicast) _announce() {
} }
// Now that we have a list of valid interfaces from the operating system, // Now that we have a list of valid interfaces from the operating system,
// we can start checking if we can send multicasts on them // we can start checking if we can send multicasts on them
for _, iface := range interfaces { for _, info := range m._interfaces {
// Find interface addresses iface := info.iface
addrs, err := iface.Addrs() for _, addr := range info.addrs {
if err != nil {
panic(err)
}
for _, addr := range addrs {
addrIP, _, _ := net.ParseCIDR(addr.String()) addrIP, _, _ := net.ParseCIDR(addr.String())
// Ignore IPv4 addresses // Ignore IPv4 addresses
if addrIP.To4() != nil { if addrIP.To4() != nil {
@ -346,7 +374,11 @@ func (m *Multicast) listen() {
if addr.IP.String() != from.IP.String() { if addr.IP.String() != from.IP.String() {
continue continue
} }
if _, ok := m.Interfaces()[from.Zone]; ok { var interfaces map[string]interfaceInfo
phony.Block(m, func() {
interfaces = m._interfaces
})
if _, ok := interfaces[from.Zone]; ok {
addr.Zone = "" addr.Zone = ""
if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil { if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil {
m.log.Debugln("Call from multicast failed:", err) m.log.Debugln("Call from multicast failed:", err)