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  }