mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Merge pull request #438 from neilalexander/multicast
Try and solidify multicast interface behavior
This commit is contained in:
		
						commit
						ac8ff740ee
					
				
					 3 changed files with 43 additions and 80 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue