From 56a24b8b640b0b74a6bba62081d69150782c740f Mon Sep 17 00:00:00 2001 From: Kleissner Date: Tue, 2 Mar 2021 04:14:22 +0100 Subject: [PATCH] Termination of networks upon removal of their network adapter. --- Network Detection.go | 37 ++++++++++++++++++++++++++++--------- Network Init.go | 1 + Network.go | 41 ++++++++++++++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/Network Detection.go b/Network Detection.go index 3aa8618..4941b81 100644 --- a/Network Detection.go +++ b/Network Detection.go @@ -170,22 +170,41 @@ func networkChangeMonitor() { // networkChangeInterfaceNew is called when a new interface is detected func networkChangeInterfaceNew(iface net.Interface, addresses []net.Addr) { - fmt.Printf("Interface new: %s\n", iface.Name) + log.Printf("networkChangeInterfaceNew new interface '%s' (%d IPs)\n", iface.Name, len(addresses)) - for _, addr := range addresses { - fmt.Printf(" IP: %s\n", addr.String()) - } } // networkChangeInterfaceRemove is called when an existing interface is removed func networkChangeInterfaceRemove(iface string, addresses []net.Addr) { - //networksMutex.RLock() - //defer networksMutex.RUnlock() + networksMutex.RLock() + defer networksMutex.RUnlock() - fmt.Printf("Interface removed: %s\n", iface) + log.Printf("networkChangeInterfaceRemove removing interface '%s' (%d IPs)\n", iface, len(addresses)) - for _, addr := range addresses { - fmt.Printf(" IP: %s\n", addr.String()) + for n, network := range networks6 { + if network.iface != nil && network.iface.Name == iface { + network.Terminate() + + // remove from list + networksNew := networks6[:n] + if n < len(networks6)-1 { + networksNew = append(networksNew, networks6[n+1:]...) + } + networks6 = networksNew + } + } + + for n, network := range networks4 { + if network.iface != nil && network.iface.Name == iface { + network.Terminate() + + // remove from list + networksNew := networks4[:n] + if n < len(networks4)-1 { + networksNew = append(networksNew, networks4[n+1:]...) + } + networks4 = networksNew + } } } diff --git a/Network Init.go b/Network Init.go index 76e8e9c..fbc952a 100644 --- a/Network Init.go +++ b/Network Init.go @@ -137,6 +137,7 @@ func networkPrepareListen(ipA string, port int) (network *Network, err error) { } network = new(Network) + network.terminateSignal = make(chan interface{}) // get the network interface that belongs to the IP if ipA != "0.0.0.0" && ipA != "::" { diff --git a/Network.go b/Network.go index fb3add6..83235d4 100644 --- a/Network.go +++ b/Network.go @@ -18,14 +18,17 @@ import ( // Network is a connection adapter through one network interface (adapter). // Note that for each IP on the same adapter separate network entries are created. type Network struct { - iface *net.Interface // Network interface belonging to the IP. May not be set. - ipnet *net.IPNet // IP network the listening address belongs to. May not be set. - address *net.UDPAddr // IP:Port where the server listens - socket *net.UDPConn // active socket for send/receive - multicastIP net.IP // Multicast IP, IPv6 only. - multicastSocket net.PacketConn // Multicast socket, IPv6 only. - broadcastSocket net.PacketConn // Broadcast socket, IPv4 only. - broadcastIPv4 []net.IP // Broadcast IPs, IPv4 only. + iface *net.Interface // Network interface belonging to the IP. May not be set. + ipnet *net.IPNet // IP network the listening address belongs to. May not be set. + address *net.UDPAddr // IP:Port where the server listens + socket *net.UDPConn // active socket for send/receive + multicastIP net.IP // Multicast IP, IPv6 only. + multicastSocket net.PacketConn // Multicast socket, IPv6 only. + broadcastSocket net.PacketConn // Broadcast socket, IPv4 only. + broadcastIPv4 []net.IP // Broadcast IPs, IPv4 only. + isTerminated bool // If true, the network was signaled for termination + terminateSignal chan interface{} // gets closed on termination signal, can be used in select via "case _ = <- network.terminateSignal:" + sync.RWMutex // for sychronized closing } // networks is a list of all connected networks @@ -92,13 +95,18 @@ const maxPacketSize = 4096 // Listen starts listening for incoming packets on the given UDP connection func (network *Network) Listen() { - for { + for !network.isTerminated { // Buffer: Must be created for each packet as it is passed as pointer. // If the buffer is too small, ReadFromUDP only reads until its length and returns this error: "wsarecvfrom: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself." buffer := make([]byte, maxPacketSize) length, sender, err := network.socket.ReadFromUDP(buffer) if err != nil { + // Exit on closed socket. Error will be "use of closed network connection". + if network.isTerminated { + return + } + log.Printf("Listen Error receiving UDP message: %v\n", err) // Only log for debug purposes. time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU. continue @@ -193,3 +201,18 @@ func (network *Network) GetAdapterName() string { } return "[unknown adapter]" } + +// Terminate sends the termination signal to all workers. It is safe to call Terminate multiple times. +func (network *Network) Terminate() { + network.Lock() + defer network.Unlock() + + if network.isTerminated { + return + } + + // set the termination signal + network.isTerminated = true + close(network.terminateSignal) // safety guaranteed via lock + network.socket.Close() // Will stop the listener from blocking on network.socket.ReadFromUDP +}