diff --git a/p2p/discover/common.go b/p2p/discover/common.go index 767cc23b92..5513afd54d 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -17,9 +17,11 @@ package discover import ( + "container/list" "crypto/ecdsa" crand "crypto/rand" "encoding/binary" + "iter" "math/rand" "net" "net/netip" @@ -143,3 +145,16 @@ func (r *reseedingRandom) Shuffle(n int, swap func(i, j int)) { defer r.mu.Unlock() r.cur.Shuffle(n, swap) } + +// iterList iterates over the elements of the given list. +func iterList[T any](l *list.List) iter.Seq2[T, *list.Element] { + return func(yield func(T, *list.Element) bool) { + for el := l.Front(); el != nil; { + next := el.Next() + if !yield(el.Value.(T), el) { + return + } + el = next + } + } +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 3a8227abc7..9e824dae18 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -446,10 +446,8 @@ func (t *UDPv4) loop() { } // Start the timer so it fires when the next pending reply has expired. now := time.Now() - for el := plist.Front(); el != nil; { - next := el.Next() - nextTimeout = el.Value.(*replyMatcher) - if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { + for p, el := range iterList[*replyMatcher](plist) { + if dist := p.deadline.Sub(now); dist < 2*respTimeout { timeout.Reset(dist) return } @@ -458,7 +456,6 @@ func (t *UDPv4) loop() { // backwards after the deadline was assigned. nextTimeout.errc <- errClockWarp plist.Remove(el) - el = next } nextTimeout = nil timeout.Stop() @@ -480,9 +477,7 @@ func (t *UDPv4) loop() { case r := <-t.gotreply: var matched bool // whether any replyMatcher considered the reply acceptable. - for el := plist.Front(); el != nil; { - next := el.Next() - p := el.Value.(*replyMatcher) + for p, el := range iterList[*replyMatcher](plist) { if p.from == r.from && p.ptype == r.data.Kind() && p.ip == r.ip { ok, requestDone := p.callback(r.data) matched = matched || ok @@ -495,7 +490,6 @@ func (t *UDPv4) loop() { // Reset the continuous timeout counter (time drift detection) contTimeouts = 0 } - el = next } r.matched <- matched @@ -503,15 +497,12 @@ func (t *UDPv4) loop() { nextTimeout = nil // Notify and remove callbacks whose deadline is in the past. - for el := plist.Front(); el != nil; { - next := el.Next() - p := el.Value.(*replyMatcher) + for p, el := range iterList[*replyMatcher](plist) { if now.After(p.deadline) || now.Equal(p.deadline) { p.errc <- errTimeout plist.Remove(el) contTimeouts++ } - el = next } // If we've accumulated too many timeouts, do an NTP time sync check if contTimeouts > ntpFailureThreshold {