diff --git a/CHANGELOG.md b/CHANGELOG.md index c779c37..b91caca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Memory leaks in the DHT fixed - Crash where ICMPv6 NDP goroutine would incorrectly start in TUN mode fixed +- Remove peers from the switch table of they stop sending switch messages but keep the TCP connection alive ## [0.2.7] - 2018-10-13 ### Added diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 9966103..920926b 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -208,6 +208,7 @@ func (t *switchTable) doMaintenance() { defer t.mutex.Unlock() // Release lock when we're done t.cleanRoot() t.cleanDropped() + t.cleanPeers() } // Updates the root periodically if it is ourself, or promotes ourself to root if we're better than the current root or if the current root has timed out. @@ -258,11 +259,33 @@ func (t *switchTable) forgetPeer(port switchPort) { if port != t.parent { return } + t.parent = 0 for _, info := range t.data.peers { t.unlockedHandleMsg(&info.msg, info.port, true) } } +// Clean all unresponsive peers from the table, needed in case a peer stops updating. +// Needed in case a non-parent peer keeps the connection open but stops sending updates. +// Also reclaims space from deleted peers by copying the map. +func (t switchTable) cleanPeers() { + now := time.Now() + for port, peer := range t.data.peers { + if now.Sub(peer.time) > switch_timeout+switch_throttle { + // Longer than switch_timeout to make sure we don't remove a working peer because the root stopped responding. + delete(t.data.peers, port) + } + } + if _, isIn := t.data.peers[t.parent]; !isIn { + // The root timestamp would probably time out before this happens, but better safe than sorry. + // We removed the current parent, so find a new one. + t.parent = 0 + for _, peer := range t.data.peers { + t.unlockedHandleMsg(&peer.msg, peer.port, true) + } + } +} + // Dropped is a list of roots that are better than the current root, but stopped sending new timestamps. // If we switch to a new root, and that root is better than an old root that previously timed out, then we can clean up the old dropped root infos. // This function is called periodically to do that cleanup. @@ -379,9 +402,6 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort, rep if !equiv(&sender.locator, &oldSender.locator) { // Reset faster info, we'll start refilling it right after this sender.faster = nil - for _, peer := range t.data.peers { - delete(peer.faster, sender.port) - } doUpdate = true } // Update the matrix of peer "faster" thresholds