mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-29 02:06:43 +00:00
230 lines
6.6 KiB
Go
230 lines
6.6 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package addressmanager
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"sync"
|
|
|
|
"github.com/kaspanet/kaspad/app/appmessage"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// AddressRandomizer is the interface for the randomizer needed for the AddressManager.
|
|
type AddressRandomizer interface {
|
|
RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress
|
|
RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress
|
|
}
|
|
|
|
// AddressKey represents a "string" key of the ip addresses
|
|
// for use as keys in maps.
|
|
type AddressKey string
|
|
|
|
// ErrAddressNotFound is an error returned from some functions when a
|
|
// given address is not found in the address manager
|
|
var ErrAddressNotFound = errors.New("address not found")
|
|
|
|
// NetAddressKey returns a key of the ip address to use it in maps.
|
|
func netAddressKey(netAddress *appmessage.NetAddress) AddressKey {
|
|
port := make([]byte, 2, 2)
|
|
binary.LittleEndian.PutUint16(port, netAddress.Port)
|
|
|
|
key := make([]byte, len(netAddress.IP), len(netAddress.IP)+len(port))
|
|
copy(key, netAddress.IP)
|
|
|
|
return AddressKey(append(key, port...))
|
|
}
|
|
|
|
// netAddressKeys returns a key of the ip address to use it in maps.
|
|
func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool {
|
|
result := make(map[AddressKey]bool, len(netAddresses))
|
|
for _, netAddress := range netAddresses {
|
|
key := netAddressKey(netAddress)
|
|
result[key] = true
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// AddressManager provides a concurrency safe address manager for caching potential
|
|
// peers on the Kaspa network.
|
|
type AddressManager struct {
|
|
addresses map[AddressKey]*appmessage.NetAddress
|
|
bannedAddresses map[AddressKey]*appmessage.NetAddress
|
|
localAddresses *localAddressManager
|
|
mutex sync.Mutex
|
|
cfg *Config
|
|
random AddressRandomizer
|
|
}
|
|
|
|
// New returns a new Kaspa address manager.
|
|
func New(cfg *Config) (*AddressManager, error) {
|
|
localAddresses, err := newLocalAddressManager(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &AddressManager{
|
|
addresses: map[AddressKey]*appmessage.NetAddress{},
|
|
bannedAddresses: map[AddressKey]*appmessage.NetAddress{},
|
|
localAddresses: localAddresses,
|
|
random: NewAddressRandomize(),
|
|
cfg: cfg,
|
|
}, nil
|
|
}
|
|
|
|
func (am *AddressManager) addAddressNoLock(address *appmessage.NetAddress) {
|
|
if !IsRoutable(address, am.cfg.AcceptUnroutable) {
|
|
return
|
|
}
|
|
|
|
key := netAddressKey(address)
|
|
_, ok := am.addresses[key]
|
|
if !ok {
|
|
am.addresses[key] = address
|
|
}
|
|
}
|
|
|
|
// AddAddress adds address to the address manager
|
|
func (am *AddressManager) AddAddress(address *appmessage.NetAddress) {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
am.addAddressNoLock(address)
|
|
}
|
|
|
|
// AddAddresses adds addresses to the address manager
|
|
func (am *AddressManager) AddAddresses(addresses ...*appmessage.NetAddress) {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
for _, address := range addresses {
|
|
am.addAddressNoLock(address)
|
|
}
|
|
}
|
|
|
|
// RemoveAddress removes addresses from the address manager
|
|
func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
key := netAddressKey(address)
|
|
delete(am.addresses, key)
|
|
delete(am.bannedAddresses, key)
|
|
}
|
|
|
|
// Addresses returns all addresses
|
|
func (am *AddressManager) Addresses() []*appmessage.NetAddress {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
result := make([]*appmessage.NetAddress, 0, len(am.addresses))
|
|
for _, address := range am.addresses {
|
|
result = append(result, address)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// BannedAddresses returns all banned addresses
|
|
func (am *AddressManager) BannedAddresses() []*appmessage.NetAddress {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
result := make([]*appmessage.NetAddress, 0, len(am.bannedAddresses))
|
|
for _, address := range am.bannedAddresses {
|
|
result = append(result, address)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// notBannedAddressesWithException returns all not banned addresses with excpetion
|
|
func (am *AddressManager) notBannedAddressesWithException(exceptions []*appmessage.NetAddress) []*appmessage.NetAddress {
|
|
exceptionsKeys := netAddressesKeys(exceptions)
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
result := make([]*appmessage.NetAddress, 0, len(am.addresses))
|
|
for key, address := range am.addresses {
|
|
if !exceptionsKeys[key] {
|
|
result = append(result, address)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// RandomAddress returns a random address that isn't banned and isn't in exceptions
|
|
func (am *AddressManager) RandomAddress(exceptions []*appmessage.NetAddress) *appmessage.NetAddress {
|
|
validAddresses := am.notBannedAddressesWithException(exceptions)
|
|
return am.random.RandomAddress(validAddresses)
|
|
}
|
|
|
|
// RandomAddresses returns count addresses at random that aren't banned and aren't in exceptions
|
|
func (am *AddressManager) RandomAddresses(count int, exceptions []*appmessage.NetAddress) []*appmessage.NetAddress {
|
|
validAddresses := am.notBannedAddressesWithException(exceptions)
|
|
return am.random.RandomAddresses(validAddresses, count)
|
|
}
|
|
|
|
// BestLocalAddress returns the most appropriate local address to use
|
|
// for the given remote address.
|
|
func (am *AddressManager) BestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress {
|
|
return am.localAddresses.bestLocalAddress(remoteAddress)
|
|
}
|
|
|
|
// Ban marks the given address as banned
|
|
func (am *AddressManager) Ban(address *appmessage.NetAddress) error {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
key := netAddressKey(address)
|
|
addressToBan, ok := am.addresses[key]
|
|
if !ok {
|
|
return errors.Wrapf(ErrAddressNotFound, "address %s "+
|
|
"is not registered with the address manager", address.TCPAddress())
|
|
}
|
|
|
|
delete(am.addresses, key)
|
|
am.bannedAddresses[key] = addressToBan
|
|
return nil
|
|
|
|
}
|
|
|
|
// Unban unmarks the given address as banned
|
|
func (am *AddressManager) Unban(address *appmessage.NetAddress) error {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
key := netAddressKey(address)
|
|
bannedAddress, ok := am.bannedAddresses[key]
|
|
if !ok {
|
|
return errors.Wrapf(ErrAddressNotFound, "address %s "+
|
|
"is not registered with the address manager as banned", address.TCPAddress())
|
|
}
|
|
|
|
delete(am.bannedAddresses, key)
|
|
am.addresses[key] = bannedAddress
|
|
return nil
|
|
}
|
|
|
|
// IsBanned returns true if the given address is marked as banned
|
|
func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) {
|
|
am.mutex.Lock()
|
|
defer am.mutex.Unlock()
|
|
|
|
key := netAddressKey(address)
|
|
if _, ok := am.bannedAddresses[key]; !ok {
|
|
if _, ok = am.addresses[key]; !ok {
|
|
return false, errors.Wrapf(ErrAddressNotFound, "address %s "+
|
|
"is not registered with the address manager", address.TCPAddress())
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|