From dfcdafa55c30e89f252f7076e32041700547c224 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 20 Dec 2018 17:37:59 -0600 Subject: [PATCH 1/3] move special peer/dht insert logic form router.go to dht.go --- src/yggdrasil/dht.go | 9 +++++++++ src/yggdrasil/router.go | 7 +------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index af104f5..ef83598 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -134,6 +134,15 @@ func (t *dht) insert(info *dhtInfo) { t.table[*info.getNodeID()] = info } +// Insert a peer into the table if it hasn't been pinged lately, to keep peers from dropping +func (t *dht) insertPeer(info *dhtInfo) { + oldInfo, isIn := t.table[*info.getNodeID()] + if !isIn || time.Since(oldInfo.recv) > 45*time.Second { + // TODO? also check coords? + t.insert(info) + } +} + // Return true if first/second/third are (partially) ordered correctly. func dht_ordered(first, second, third *crypto.NodeID) bool { lessOrEqual := func(first, second *crypto.NodeID) bool { diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 6c92869..87da882 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -110,12 +110,7 @@ func (r *router) mainLoop() { case p := <-r.send: r.sendPacket(p) case info := <-r.core.dht.peers: - now := time.Now() - oldInfo, isIn := r.core.dht.table[*info.getNodeID()] - r.core.dht.insert(info) - if isIn && now.Sub(oldInfo.recv) < 45*time.Second { - info.recv = oldInfo.recv - } + r.core.dht.insertPeer(info) case <-r.reset: r.core.sessions.resetInits() r.core.dht.reset() From f59852b1e1573eb490642f1f2ae0a8f5f5bbd363 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 20 Dec 2018 20:16:51 -0600 Subject: [PATCH 2/3] adjust how dht throttle works, it should now back off faster, and back off even more if things are not in use --- src/yggdrasil/dht.go | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index ef83598..e360cec 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -12,7 +12,12 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) -const dht_lookup_size = 16 +const ( + dht_lookup_size = 16 + dht_timeout = 6 * time.Minute + dht_max_delay = 5 * time.Minute + dht_max_delay_dirty = 30 * time.Second +) // dhtInfo represents everything we know about a node in the DHT. // This includes its key, a cache of it's NodeID, coords, and timing/ping related info for deciding who/when to ping nodes for maintenance. @@ -23,6 +28,7 @@ type dhtInfo struct { recv time.Time // When we last received a message pings int // Time out if at least 3 consecutive maintenance pings drop throttle time.Duration + dirty bool // Set to true if we've used this node in ping responses (for queries about someone other than the person doing the asking, i.e. real searches) since the last time we heard from the node } // Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times. @@ -137,7 +143,7 @@ func (t *dht) insert(info *dhtInfo) { // Insert a peer into the table if it hasn't been pinged lately, to keep peers from dropping func (t *dht) insertPeer(info *dhtInfo) { oldInfo, isIn := t.table[*info.getNodeID()] - if !isIn || time.Since(oldInfo.recv) > 45*time.Second { + if !isIn || time.Since(oldInfo.recv) > dht_max_delay+30*time.Second { // TODO? also check coords? t.insert(info) } @@ -194,6 +200,14 @@ func (t *dht) handleReq(req *dhtReq) { if _, isIn := t.table[*info.getNodeID()]; !isIn && t.isImportant(&info) { t.ping(&info, nil) } + // Maybe mark nodes from lookup as dirty + if req.Dest != *info.getNodeID() { + // This node asked about someone other than themself, so this wasn't just idle traffic. + for _, info := range res.Infos { + // Mark nodes dirty so we're sure to check up on them again later + info.dirty = true + } + } } // Sends a lookup response to the specified node. @@ -311,19 +325,24 @@ func (t *dht) doMaintenance() { } t.callbacks = newCallbacks for infoID, info := range t.table { - if now.Sub(info.recv) > time.Minute || info.pings > 3 { + if now.Sub(info.recv) > dht_timeout || info.pings > 6 { delete(t.table, infoID) t.imp = nil } } for _, info := range t.getImportant() { - if now.Sub(info.recv) > info.throttle { + switch { + case now.Sub(info.recv) > info.throttle: + info.throttle *= 2 + if info.throttle < time.Second { + info.throttle = time.Second + } else if info.throttle > dht_max_delay { + info.throttle = dht_max_delay + } + fallthrough + case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty: t.ping(info, nil) info.pings++ - info.throttle += time.Second - if info.throttle > 30*time.Second { - info.throttle = 30 * time.Second - } } } } From 59093aa43b69fa33c93efe65347e24fc4a027d4f Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 21 Dec 2018 17:45:24 -0600 Subject: [PATCH 3/3] clean up node info immediately if it reaches the timeout or if it needs refreshing but won't be pinged due to being unimportant --- src/yggdrasil/dht.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index e360cec..9688394 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -325,7 +325,15 @@ func (t *dht) doMaintenance() { } t.callbacks = newCallbacks for infoID, info := range t.table { - if now.Sub(info.recv) > dht_timeout || info.pings > 6 { + switch { + case info.pings > 6: + // It failed to respond to too many pings + fallthrough + case now.Sub(info.recv) > dht_timeout: + // It's too old + fallthrough + case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty && !t.isImportant(info): + // We won't ping it to refresh it, so just drop it delete(t.table, infoID) t.imp = nil }