From 12486b055734f92c1622af9128f28f8376f75d02 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 6 Jul 2019 11:52:30 +0100 Subject: [PATCH] Try to more gracefully handle shutdowns on Windows --- cmd/yggdrasil/main.go | 16 +++++++++------- src/multicast/multicast.go | 7 +++++++ src/tuntap/iface.go | 6 ++++++ src/tuntap/tun.go | 10 ++++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 6af27725..fd8828c8 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -231,11 +231,6 @@ func main() { } else { logger.Errorln("Unable to get Listener:", err) } - // The Stop function ensures that the TUN/TAP adapter is correctly shut down - // before the program exits. - defer func() { - n.core.Stop() - }() // Make some nice output that tells us what our IPv6 address and subnet are. // This is just logged to stdout for the user. address := n.core.Address() @@ -256,6 +251,8 @@ func main() { // deferred Stop function above will run which will shut down TUN/TAP. for { select { + case _ = <-c: + goto exit case _ = <-r: if *useconffile != "" { cfg = readConfig(useconf, useconffile, normaliseconf) @@ -265,11 +262,16 @@ func main() { } else { logger.Errorln("Reloading config at runtime is only possible with -useconffile") } - case _ = <-c: - goto exit } } exit: + // When gracefully shutting down we should try and clean up as much as + // possible, although not all of these functions are necessarily implemented + // yet + n.core.Stop() + n.admin.Stop() + n.multicast.Stop() + n.tuntap.Stop() } func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool { diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 3c0d8c0f..ba1f18fb 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -26,6 +26,7 @@ type Multicast struct { groupAddr string listeners map[string]*yggdrasil.TcpListener listenPort uint16 + isOpen bool } // Init prepares the multicast interface for use. @@ -61,6 +62,7 @@ func (m *Multicast) Start() error { // Windows can't set this flag, so we need to handle it in other ways } + m.isOpen = true go m.multicastStarted() go m.listen() go m.announce() @@ -70,6 +72,8 @@ func (m *Multicast) Start() error { // Stop is not implemented for multicast yet. func (m *Multicast) Stop() error { + m.isOpen = false + m.sock.Close() return nil } @@ -246,6 +250,9 @@ func (m *Multicast) listen() { for { nBytes, rcm, fromAddr, err := m.sock.ReadFrom(bs) if err != nil { + if !m.isOpen { + return + } panic(err) } if rcm != nil { diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 16a3b65d..60c814c2 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -98,6 +98,9 @@ func (tun *TunAdapter) writer() error { util.PutBytes(b) } if err != nil { + if !tun.isOpen { + return err + } tun.log.Errorln("TUN/TAP iface write error:", err) continue } @@ -114,6 +117,9 @@ func (tun *TunAdapter) reader() error { // Wait for a packet to be delivered to us through the TUN/TAP adapter n, err := tun.iface.Read(bs) if err != nil { + if !tun.isOpen { + return err + } panic(err) } if n == 0 { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index ed5d2d45..b7b4cfa6 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -181,6 +181,16 @@ func (tun *TunAdapter) Start() error { return nil } +// Start the setup process for the TUN/TAP adapter. If successful, starts the +// read/write goroutines to handle packets on that interface. +func (tun *TunAdapter) Stop() error { + tun.isOpen = false + // TODO: we have nothing that cleanly stops all the various goroutines opened + // by TUN/TAP, e.g. readers/writers, sessions + tun.iface.Close() + return nil +} + // UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig // and then signals the various module goroutines to reconfigure themselves if // needed.