mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Allow multicast to be shut down more sanely
This commit is contained in:
		
							parent
							
								
									00a972b74e
								
							
						
					
					
						commit
						366fe7e772
					
				
					 2 changed files with 113 additions and 118 deletions
				
			
		| 
						 | 
					@ -19,14 +19,16 @@ 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
 | 
				
			||||||
	isOpen     bool
 | 
						isOpen          bool
 | 
				
			||||||
 | 
						announcer       *time.Timer
 | 
				
			||||||
 | 
						platformhandler *time.Timer
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Init prepares the multicast interface for use.
 | 
					// Init prepares the multicast interface for use.
 | 
				
			||||||
| 
						 | 
					@ -63,9 +65,9 @@ func (m *Multicast) Start() error {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.isOpen = true
 | 
						m.isOpen = true
 | 
				
			||||||
	go m.multicastStarted()
 | 
					 | 
				
			||||||
	go m.listen()
 | 
						go m.listen()
 | 
				
			||||||
	go m.announce()
 | 
						m.multicastStarted()
 | 
				
			||||||
 | 
						m.announce()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -73,6 +75,8 @@ func (m *Multicast) Start() error {
 | 
				
			||||||
// Stop is not implemented for multicast yet.
 | 
					// Stop is not implemented for multicast yet.
 | 
				
			||||||
func (m *Multicast) Stop() error {
 | 
					func (m *Multicast) Stop() error {
 | 
				
			||||||
	m.isOpen = false
 | 
						m.isOpen = false
 | 
				
			||||||
 | 
						m.announcer.Stop()
 | 
				
			||||||
 | 
						m.platformhandler.Stop()
 | 
				
			||||||
	m.sock.Close()
 | 
						m.sock.Close()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -136,108 +140,106 @@ func (m *Multicast) announce() {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	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 {
 | 
							// Prepare our stop function!
 | 
				
			||||||
			// Prepare our stop function!
 | 
							stop := func() {
 | 
				
			||||||
			stop := func() {
 | 
								listener.Stop <- true
 | 
				
			||||||
				listener.Stop <- true
 | 
								delete(m.listeners, name)
 | 
				
			||||||
				delete(m.listeners, name)
 | 
								m.log.Debugln("No longer multicasting on", name)
 | 
				
			||||||
				m.log.Debugln("No longer multicasting on", name)
 | 
							}
 | 
				
			||||||
			}
 | 
							// 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 := interfaces[name]; !ok {
 | 
								stop()
 | 
				
			||||||
				stop()
 | 
								continue
 | 
				
			||||||
				continue
 | 
							}
 | 
				
			||||||
			}
 | 
							// It's possible that the link-local listener address has changed so if
 | 
				
			||||||
			// It's possible that the link-local listener address has changed so if
 | 
							// that is the case then we should clean up the interface listener
 | 
				
			||||||
			// that is the case then we should clean up the interface listener
 | 
							found := false
 | 
				
			||||||
			found := false
 | 
							listenaddr, err := net.ResolveTCPAddr("tcp6", listener.Listener.Addr().String())
 | 
				
			||||||
			listenaddr, err := net.ResolveTCPAddr("tcp6", listener.Listener.Addr().String())
 | 
							if err != nil {
 | 
				
			||||||
			if err != nil {
 | 
								stop()
 | 
				
			||||||
				stop()
 | 
								continue
 | 
				
			||||||
				continue
 | 
							}
 | 
				
			||||||
			}
 | 
							// Find the interface that matches the listener
 | 
				
			||||||
			// Find the interface that matches the listener
 | 
							if intf, err := net.InterfaceByName(name); err == nil {
 | 
				
			||||||
			if intf, err := net.InterfaceByName(name); err == nil {
 | 
								if addrs, err := intf.Addrs(); err == nil {
 | 
				
			||||||
				if addrs, err := intf.Addrs(); err == nil {
 | 
									// Loop through the addresses attached to that listener and see if any
 | 
				
			||||||
					// Loop through the addresses attached to that listener and see if any
 | 
									// of them match the current address of the listener
 | 
				
			||||||
					// of them match the current address of the listener
 | 
									for _, addr := range addrs {
 | 
				
			||||||
					for _, addr := range addrs {
 | 
										if ip, _, err := net.ParseCIDR(addr.String()); err == nil {
 | 
				
			||||||
						if ip, _, err := net.ParseCIDR(addr.String()); err == nil {
 | 
											// Does the interface address match our listener address?
 | 
				
			||||||
							// Does the interface address match our listener address?
 | 
											if ip.Equal(listenaddr.IP) {
 | 
				
			||||||
							if ip.Equal(listenaddr.IP) {
 | 
												found = true
 | 
				
			||||||
								found = true
 | 
												break
 | 
				
			||||||
								break
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// If the address has not been found on the adapter then we should stop
 | 
					 | 
				
			||||||
			// and clean up the TCP listener. A new one will be created below if a
 | 
					 | 
				
			||||||
			// suitable link-local address is found
 | 
					 | 
				
			||||||
			if !found {
 | 
					 | 
				
			||||||
				stop()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Now that we have a list of valid interfaces from the operating system,
 | 
							// If the address has not been found on the adapter then we should stop
 | 
				
			||||||
		// we can start checking if we can send multicasts on them
 | 
							// and clean up the TCP listener. A new one will be created below if a
 | 
				
			||||||
		for _, iface := range interfaces {
 | 
							// suitable link-local address is found
 | 
				
			||||||
			// Find interface addresses
 | 
							if !found {
 | 
				
			||||||
			addrs, err := iface.Addrs()
 | 
								stop()
 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				panic(err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			for _, addr := range addrs {
 | 
					 | 
				
			||||||
				addrIP, _, _ := net.ParseCIDR(addr.String())
 | 
					 | 
				
			||||||
				// Ignore IPv4 addresses
 | 
					 | 
				
			||||||
				if addrIP.To4() != nil {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// Ignore non-link-local addresses
 | 
					 | 
				
			||||||
				if !addrIP.IsLinkLocalUnicast() {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// Join the multicast group
 | 
					 | 
				
			||||||
				m.sock.JoinGroup(&iface, groupAddr)
 | 
					 | 
				
			||||||
				// Try and see if we already have a TCP listener for this interface
 | 
					 | 
				
			||||||
				var listener *yggdrasil.TcpListener
 | 
					 | 
				
			||||||
				if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil {
 | 
					 | 
				
			||||||
					// No listener was found - let's create one
 | 
					 | 
				
			||||||
					listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort)
 | 
					 | 
				
			||||||
					if li, err := m.core.ListenTCP(listenaddr); err == nil {
 | 
					 | 
				
			||||||
						m.log.Debugln("Started multicasting on", iface.Name)
 | 
					 | 
				
			||||||
						// Store the listener so that we can stop it later if needed
 | 
					 | 
				
			||||||
						m.listeners[iface.Name] = li
 | 
					 | 
				
			||||||
						listener = li
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					// An existing listener was found
 | 
					 | 
				
			||||||
					listener = m.listeners[iface.Name]
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// Make sure nothing above failed for some reason
 | 
					 | 
				
			||||||
				if listener == nil {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// Get the listener details and construct the multicast beacon
 | 
					 | 
				
			||||||
				lladdr := listener.Listener.Addr().String()
 | 
					 | 
				
			||||||
				if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil {
 | 
					 | 
				
			||||||
					a.Zone = ""
 | 
					 | 
				
			||||||
					destAddr.Zone = iface.Name
 | 
					 | 
				
			||||||
					msg := []byte(a.String())
 | 
					 | 
				
			||||||
					m.sock.WriteTo(msg, nil, destAddr)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				break
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		time.Sleep(time.Second * 15)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// Now that we have a list of valid interfaces from the operating system,
 | 
				
			||||||
 | 
						// we can start checking if we can send multicasts on them
 | 
				
			||||||
 | 
						for _, iface := range interfaces {
 | 
				
			||||||
 | 
							// Find interface addresses
 | 
				
			||||||
 | 
							addrs, err := iface.Addrs()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, addr := range addrs {
 | 
				
			||||||
 | 
								addrIP, _, _ := net.ParseCIDR(addr.String())
 | 
				
			||||||
 | 
								// Ignore IPv4 addresses
 | 
				
			||||||
 | 
								if addrIP.To4() != nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Ignore non-link-local addresses
 | 
				
			||||||
 | 
								if !addrIP.IsLinkLocalUnicast() {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Join the multicast group
 | 
				
			||||||
 | 
								m.sock.JoinGroup(&iface, groupAddr)
 | 
				
			||||||
 | 
								// Try and see if we already have a TCP listener for this interface
 | 
				
			||||||
 | 
								var listener *yggdrasil.TcpListener
 | 
				
			||||||
 | 
								if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil {
 | 
				
			||||||
 | 
									// No listener was found - let's create one
 | 
				
			||||||
 | 
									listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort)
 | 
				
			||||||
 | 
									if li, err := m.core.ListenTCP(listenaddr); err == nil {
 | 
				
			||||||
 | 
										m.log.Debugln("Started multicasting on", iface.Name)
 | 
				
			||||||
 | 
										// Store the listener so that we can stop it later if needed
 | 
				
			||||||
 | 
										m.listeners[iface.Name] = li
 | 
				
			||||||
 | 
										listener = li
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									// An existing listener was found
 | 
				
			||||||
 | 
									listener = m.listeners[iface.Name]
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Make sure nothing above failed for some reason
 | 
				
			||||||
 | 
								if listener == nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Get the listener details and construct the multicast beacon
 | 
				
			||||||
 | 
								lladdr := listener.Listener.Addr().String()
 | 
				
			||||||
 | 
								if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil {
 | 
				
			||||||
 | 
									a.Zone = ""
 | 
				
			||||||
 | 
									destAddr.Zone = iface.Name
 | 
				
			||||||
 | 
									msg := []byte(a.String())
 | 
				
			||||||
 | 
									m.sock.WriteTo(msg, nil, destAddr)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m.announcer = time.AfterFunc(time.Second*15, m.announce)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Multicast) listen() {
 | 
					func (m *Multicast) listen() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,21 +32,14 @@ import (
 | 
				
			||||||
var awdlGoroutineStarted bool
 | 
					var awdlGoroutineStarted bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Multicast) multicastStarted() {
 | 
					func (m *Multicast) multicastStarted() {
 | 
				
			||||||
	if awdlGoroutineStarted {
 | 
						C.StopAWDLBrowsing()
 | 
				
			||||||
		return
 | 
						for intf := range m.Interfaces() {
 | 
				
			||||||
	}
 | 
							if intf == "awdl0" {
 | 
				
			||||||
	awdlGoroutineStarted = true
 | 
								C.StartAWDLBrowsing()
 | 
				
			||||||
	for {
 | 
								break
 | 
				
			||||||
		C.StopAWDLBrowsing()
 | 
					 | 
				
			||||||
		for intf := range m.Interfaces() {
 | 
					 | 
				
			||||||
			if intf == "awdl0" {
 | 
					 | 
				
			||||||
				m.log.Infoln("Multicast discovery is using AWDL discovery")
 | 
					 | 
				
			||||||
				C.StartAWDLBrowsing()
 | 
					 | 
				
			||||||
				break
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		time.Sleep(time.Minute)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						m.platformhandler = time.AfterFunc(time.Minute, m.multicastStarted)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
 | 
					func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue