github.com/MetalBlockchain/metalgo@v1.11.9/network/tracked_ip.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package network 5 6 import ( 7 "math/rand" 8 "net/netip" 9 "sync" 10 "time" 11 ) 12 13 func init() { 14 rand.Seed(time.Now().UnixNano()) 15 } 16 17 type trackedIP struct { 18 delayLock sync.RWMutex 19 delay time.Duration 20 21 ip netip.AddrPort 22 23 stopTrackingOnce sync.Once 24 onStopTracking chan struct{} 25 } 26 27 func newTrackedIP(ip netip.AddrPort) *trackedIP { 28 return &trackedIP{ 29 ip: ip, 30 onStopTracking: make(chan struct{}), 31 } 32 } 33 34 func (ip *trackedIP) trackNewIP(newIP netip.AddrPort) *trackedIP { 35 ip.stopTracking() 36 return &trackedIP{ 37 delay: ip.getDelay(), 38 ip: newIP, 39 onStopTracking: make(chan struct{}), 40 } 41 } 42 43 func (ip *trackedIP) getDelay() time.Duration { 44 ip.delayLock.RLock() 45 delay := ip.delay 46 ip.delayLock.RUnlock() 47 return delay 48 } 49 50 func (ip *trackedIP) increaseDelay(initialDelay, maxDelay time.Duration) { 51 ip.delayLock.Lock() 52 defer ip.delayLock.Unlock() 53 54 // If the timeout was previously 0, ensure that there is a reasonable delay. 55 if ip.delay <= 0 { 56 ip.delay = initialDelay 57 } 58 59 // Randomization is only performed here to distribute reconnection 60 // attempts to a node that previously shut down. This doesn't 61 // require cryptographically secure random number generation. 62 // set the timeout to [1, 2) * timeout 63 ip.delay = time.Duration(float64(ip.delay) * (1 + rand.Float64())) // #nosec G404 64 if ip.delay > maxDelay { 65 // set the timeout to [.75, 1) * maxDelay 66 ip.delay = time.Duration(float64(maxDelay) * (3 + rand.Float64()) / 4) // #nosec G404 67 } 68 } 69 70 func (ip *trackedIP) stopTracking() { 71 ip.stopTrackingOnce.Do(func() { 72 close(ip.onStopTracking) 73 }) 74 }