5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-26 07:11:40 +00:00

Merge pull request #438 from neilalexander/multicast

Try and solidify multicast interface behavior
This commit is contained in:
Neil Alexander 2019-06-29 00:38:38 +01:00 committed by GitHub
commit ac8ff740ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 80 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.interfaces() { 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

@ -19,14 +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
reconfigure chan chan error sock *ipv6.PacketConn
sock *ipv6.PacketConn groupAddr string
groupAddr string listeners map[string]*yggdrasil.TcpListener
listeners map[string]*yggdrasil.TcpListener listenPort uint16
listenPort uint16
} }
// Init prepares the multicast interface for use. // Init prepares the multicast interface for use.
@ -34,25 +33,10 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log
m.core = core m.core = core
m.config = state m.config = state
m.log = log m.log = log
m.reconfigure = make(chan chan error, 1)
m.listeners = make(map[string]*yggdrasil.TcpListener) m.listeners = make(map[string]*yggdrasil.TcpListener)
current, _ := m.config.Get() current, _ := m.config.Get()
m.listenPort = current.LinkLocalTCPPort m.listenPort = current.LinkLocalTCPPort
go func() {
for {
e := <-m.reconfigure
// There's nothing particularly to do here because the multicast module
// already consults the config.NodeState when enumerating multicast
// interfaces on each pass. We just need to return nil so that the
// reconfiguration doesn't block indefinitely
e <- nil
}
}()
m.groupAddr = "[ff02::114]:9001" m.groupAddr = "[ff02::114]:9001"
// Check if we've been given any expressions
if count := len(m.interfaces()); count != 0 {
m.log.Infoln("Found", count, "multicast interface(s)")
}
return nil return nil
} }
@ -60,32 +44,27 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log
// listen for multicast beacons from other hosts and will advertise multicast // listen for multicast beacons from other hosts and will advertise multicast
// beacons out to the network. // beacons out to the network.
func (m *Multicast) Start() error { func (m *Multicast) Start() error {
current, _ := m.config.Get() addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
if len(current.MulticastInterfaces) == 0 { if err != nil {
m.log.Infoln("Multicast discovery is disabled") return err
} else {
m.log.Infoln("Multicast discovery is enabled")
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
if err != nil {
return err
}
listenString := fmt.Sprintf("[::]:%v", addr.Port)
lc := net.ListenConfig{
Control: m.multicastReuse,
}
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
if err != nil {
return err
}
m.sock = ipv6.NewPacketConn(conn)
if err = m.sock.SetControlMessage(ipv6.FlagDst, true); err != nil {
// Windows can't set this flag, so we need to handle it in other ways
}
go m.multicastStarted()
go m.listen()
go m.announce()
} }
listenString := fmt.Sprintf("[::]:%v", addr.Port)
lc := net.ListenConfig{
Control: m.multicastReuse,
}
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
if err != nil {
return err
}
m.sock = ipv6.NewPacketConn(conn)
if err = m.sock.SetControlMessage(ipv6.FlagDst, true); err != nil {
// Windows can't set this flag, so we need to handle it in other ways
}
go m.multicastStarted()
go m.listen()
go m.announce()
return nil return nil
} }
@ -99,37 +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")
errors := 0
components := []chan chan error{
m.reconfigure,
}
for _, component := range components {
response := make(chan error)
component <- response
if err := <-response; err != nil {
m.log.Errorln(err)
errors++
}
}
if errors > 0 {
m.log.Warnln(errors, "multicast module(s) reported errors during configuration reload")
} else {
m.log.Infoln("Multicast configuration reloaded successfully")
}
} }
func (m *Multicast) interfaces() map[string]net.Interface { // GetInterfaces returns the currently known/enabled multicast interfaces. It is
// expected that UpdateInterfaces has been called at least once before calling
// this method.
func (m *Multicast) Interfaces() map[string]net.Interface {
interfaces := make(map[string]net.Interface)
// 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
interfaces := make(map[string]net.Interface)
allifaces, err := net.Interfaces() allifaces, err := net.Interfaces()
if err != nil { if err != nil {
panic(err) panic(err)
@ -173,7 +134,7 @@ func (m *Multicast) announce() {
panic(err) panic(err)
} }
for { for {
interfaces := m.interfaces() 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 {
@ -307,9 +268,11 @@ func (m *Multicast) listen() {
if addr.IP.String() != from.IP.String() { if addr.IP.String() != from.IP.String() {
continue continue
} }
addr.Zone = "" if _, ok := m.Interfaces()[from.Zone]; ok {
if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil { addr.Zone = ""
m.log.Debugln("Call from multicast failed:", err) if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil {
m.log.Debugln("Call from multicast failed:", err)
}
} }
} }
} }

View File

@ -35,12 +35,12 @@ func (m *Multicast) multicastStarted() {
if awdlGoroutineStarted { if awdlGoroutineStarted {
return return
} }
m.log.Infoln("Multicast discovery will wake up AWDL if required")
awdlGoroutineStarted = true awdlGoroutineStarted = true
for { for {
C.StopAWDLBrowsing() C.StopAWDLBrowsing()
for _, intf := range m.interfaces() { for intf := range m.Interfaces() {
if intf.Name == "awdl0" { if intf == "awdl0" {
m.log.Infoln("Multicast discovery is using AWDL discovery")
C.StartAWDLBrowsing() C.StartAWDLBrowsing()
break break
} }