Return new copy of interfaces on each Interfaces() call

This commit is contained in:
Neil Alexander 2019-06-29 00:12:56 +01:00
parent 54f1804101
commit 27b3b9b49b
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
3 changed files with 16 additions and 56 deletions

View File

@ -5,7 +5,7 @@ import "github.com/yggdrasil-network/yggdrasil-go/src/admin"
func (m *Multicast) SetupAdminHandlers(a *admin.AdminSocket) { func (m *Multicast) SetupAdminHandlers(a *admin.AdminSocket) {
a.AddHandler("getMulticastInterfaces", []string{}, func(in admin.Info) (admin.Info, error) { a.AddHandler("getMulticastInterfaces", []string{}, func(in admin.Info) (admin.Info, error) {
var intfs []string var intfs []string
for _, v := range m.GetInterfaces() { for _, v := range m.Interfaces() {
intfs = append(intfs, v.Name) intfs = append(intfs, v.Name)
} }
return admin.Info{"multicast_interfaces": intfs}, nil return admin.Info{"multicast_interfaces": intfs}, nil

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net" "net"
"regexp" "regexp"
"sync"
"time" "time"
"github.com/gologme/log" "github.com/gologme/log"
@ -20,16 +19,13 @@ import (
// configured multicast interface, Yggdrasil will attempt to peer with that node // configured multicast interface, Yggdrasil will attempt to peer with that node
// automatically. // automatically.
type Multicast struct { type Multicast struct {
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]*yggdrasil.TcpListener listeners map[string]*yggdrasil.TcpListener
listenPort uint16 listenPort uint16
interfaces map[string]net.Interface
interfacesMutex sync.RWMutex
interfacesTime time.Time
} }
// Init prepares the multicast interface for use. // Init prepares the multicast interface for use.
@ -38,23 +34,9 @@ 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]*yggdrasil.TcpListener) m.listeners = make(map[string]*yggdrasil.TcpListener)
m.interfaces = make(map[string]net.Interface)
current, _ := m.config.Get() current, _ := m.config.Get()
m.listenPort = current.LinkLocalTCPPort m.listenPort = current.LinkLocalTCPPort
m.groupAddr = "[ff02::114]:9001" m.groupAddr = "[ff02::114]:9001"
// Perform our first check for multicast interfaces
if count := m.UpdateInterfaces(); count != 0 {
m.log.Infoln("Found", count, "multicast interface(s)")
} else {
m.log.Infoln("Multicast is not enabled on any interfaces")
}
// Keep checking quietly every minute in case they change
go func() {
for {
time.Sleep(time.Minute)
m.UpdateInterfaces()
}
}()
return nil return nil
} }
@ -96,40 +78,19 @@ func (m *Multicast) Stop() error {
// needed. // needed.
func (m *Multicast) UpdateConfig(config *config.NodeConfig) { func (m *Multicast) UpdateConfig(config *config.NodeConfig) {
m.log.Debugln("Reloading multicast configuration...") m.log.Debugln("Reloading multicast configuration...")
m.config.Replace(*config) m.config.Replace(*config)
m.log.Infoln("Multicast configuration reloaded successfully") m.log.Infoln("Multicast configuration reloaded successfully")
if count := m.UpdateInterfaces(); count != 0 {
m.log.Infoln("Found", count, "multicast interface(s)")
} else {
m.log.Infoln("Multicast is not enabled on any interfaces")
}
} }
// GetInterfaces returns the currently known/enabled multicast interfaces. It is // GetInterfaces returns the currently known/enabled multicast interfaces. It is
// expected that UpdateInterfaces has been called at least once before calling // expected that UpdateInterfaces has been called at least once before calling
// this method. // this method.
func (m *Multicast) GetInterfaces() map[string]net.Interface { func (m *Multicast) Interfaces() map[string]net.Interface {
m.interfacesMutex.RLock() interfaces := make(map[string]net.Interface)
defer m.interfacesMutex.RUnlock()
return m.interfaces
}
// UpdateInterfaces re-enumerates the available multicast interfaces on the
// system, using the current MulticastInterfaces config option as a template.
// The number of selected interfaces is returned.
func (m *Multicast) UpdateInterfaces() int {
m.interfacesMutex.Lock()
defer m.interfacesMutex.Unlock()
// Get interface expressions from config // Get interface expressions from config
current, _ := m.config.Get() current, _ := m.config.Get()
exprs := current.MulticastInterfaces exprs := current.MulticastInterfaces
// Ask the system for network interfaces // Ask the system for network interfaces
for i := range m.interfaces {
delete(m.interfaces, i)
}
allifaces, err := net.Interfaces() allifaces, err := net.Interfaces()
if err != nil { if err != nil {
panic(err) panic(err)
@ -156,12 +117,11 @@ func (m *Multicast) UpdateInterfaces() int {
} }
// Does the interface match the regular expression? Store it if so // Does the interface match the regular expression? Store it if so
if e.MatchString(iface.Name) { if e.MatchString(iface.Name) {
m.interfaces[iface.Name] = iface interfaces[iface.Name] = iface
} }
} }
} }
m.interfacesTime = time.Now() return interfaces
return len(m.interfaces)
} }
func (m *Multicast) announce() { func (m *Multicast) announce() {
@ -174,7 +134,7 @@ func (m *Multicast) announce() {
panic(err) panic(err)
} }
for { for {
interfaces := m.GetInterfaces() 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, listener := range m.listeners { for name, listener := range m.listeners {
@ -308,7 +268,7 @@ func (m *Multicast) listen() {
if addr.IP.String() != from.IP.String() { if addr.IP.String() != from.IP.String() {
continue continue
} }
if _, ok := m.GetInterfaces()[from.Zone]; ok { if _, ok := m.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)

View File

@ -38,8 +38,8 @@ func (m *Multicast) multicastStarted() {
awdlGoroutineStarted = true awdlGoroutineStarted = true
for { for {
C.StopAWDLBrowsing() C.StopAWDLBrowsing()
for _, intf := range m.GetInterfaces() { for intf := range m.Interfaces() {
if intf.Name == "awdl0" { if intf == "awdl0" {
m.log.Infoln("Multicast discovery is using AWDL discovery") m.log.Infoln("Multicast discovery is using AWDL discovery")
C.StartAWDLBrowsing() C.StartAWDLBrowsing()
break break