mirror of https://github.com/poanetwork/gecko.git
281 lines
6.7 KiB
Go
281 lines
6.7 KiB
Go
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package networking
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/ava-labs/salticidae-go"
|
|
|
|
"github.com/ava-labs/gecko/ids"
|
|
"github.com/ava-labs/gecko/utils"
|
|
)
|
|
|
|
// Connections provides an interface for what a group of connections will
|
|
// support.
|
|
type Connections interface {
|
|
Add(salticidae.PeerID, ids.ShortID, utils.IPDesc)
|
|
|
|
GetPeerID(ids.ShortID) (salticidae.PeerID, bool)
|
|
GetID(salticidae.PeerID) (ids.ShortID, bool)
|
|
|
|
ContainsPeerID(salticidae.PeerID) bool
|
|
ContainsID(ids.ShortID) bool
|
|
ContainsIP(utils.IPDesc) bool
|
|
|
|
Remove(salticidae.PeerID, ids.ShortID)
|
|
RemovePeerID(salticidae.PeerID)
|
|
RemoveID(ids.ShortID)
|
|
|
|
PeerIDs() []salticidae.PeerID
|
|
IDs() ids.ShortSet
|
|
IPs() []utils.IPDesc
|
|
Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc)
|
|
|
|
Len() int
|
|
}
|
|
|
|
type connections struct {
|
|
mux sync.Mutex
|
|
// peerID -> id
|
|
peerIDToID map[[32]byte]ids.ShortID
|
|
// id -> peerID
|
|
idToPeerID map[[20]byte]salticidae.PeerID
|
|
// id -> ip
|
|
idToIP map[[20]byte]utils.IPDesc
|
|
}
|
|
|
|
// NewConnections returns a new and empty connections object
|
|
func NewConnections() Connections {
|
|
return &connections{
|
|
peerIDToID: make(map[[32]byte]ids.ShortID),
|
|
idToPeerID: make(map[[20]byte]salticidae.PeerID),
|
|
idToIP: make(map[[20]byte]utils.IPDesc),
|
|
}
|
|
}
|
|
|
|
// Add Assumes that peer is garbage collected normally
|
|
func (c *connections) Add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
c.add(peer, id, ip)
|
|
}
|
|
|
|
// GetPeerID returns the peer mapped to the id that is provided if one exists.
|
|
func (c *connections) GetPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.getPeerID(id)
|
|
}
|
|
|
|
// GetID returns the id mapped to the peer that is provided if one exists.
|
|
func (c *connections) GetID(peer salticidae.PeerID) (ids.ShortID, bool) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.getID(peer)
|
|
}
|
|
|
|
// ContainsPeerID returns true if the peer is contained in the connection pool
|
|
func (c *connections) ContainsPeerID(peer salticidae.PeerID) bool {
|
|
_, exists := c.GetID(peer)
|
|
return exists
|
|
}
|
|
|
|
// ContainsID returns true if the id is contained in the connection pool
|
|
func (c *connections) ContainsID(id ids.ShortID) bool {
|
|
_, exists := c.GetPeerID(id)
|
|
return exists
|
|
}
|
|
|
|
// ContainsIP returns true if the ip is contained in the connection pool
|
|
func (c *connections) ContainsIP(ip utils.IPDesc) bool {
|
|
for _, otherIP := range c.IPs() {
|
|
if ip.Equal(otherIP) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Remove ensures that no connection will have any mapping containing [peer] or
|
|
// [id].
|
|
func (c *connections) Remove(peer salticidae.PeerID, id ids.ShortID) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
c.remove(peer, id)
|
|
}
|
|
|
|
// RemovePeerID ensures that no connection will have a mapping containing [peer]
|
|
func (c *connections) RemovePeerID(peer salticidae.PeerID) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
c.removePeerID(peer)
|
|
}
|
|
|
|
// RemoveID ensures that no connection will have a mapping containing [id]
|
|
func (c *connections) RemoveID(id ids.ShortID) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
c.removeID(id)
|
|
}
|
|
|
|
// PeerIDs returns the full list of peers contained in this connection pool.
|
|
func (c *connections) PeerIDs() []salticidae.PeerID {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.peerIDs()
|
|
}
|
|
|
|
// IDs return the set of IDs that are mapping in this connection pool.
|
|
func (c *connections) IDs() ids.ShortSet {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.ids()
|
|
}
|
|
|
|
// IPs return the set of IPs that are mapped in this connection pool.
|
|
func (c *connections) IPs() []utils.IPDesc {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.ips()
|
|
}
|
|
|
|
// Conns return the set of connections in this connection pool.
|
|
func (c *connections) Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.conns()
|
|
}
|
|
|
|
// Len returns the number of elements in the map
|
|
func (c *connections) Len() int {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
return c.len()
|
|
}
|
|
|
|
func (c *connections) add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
|
|
c.remove(peer, id)
|
|
|
|
key := id.Key()
|
|
c.peerIDToID[toID(peer)] = id
|
|
c.idToPeerID[key] = peer
|
|
c.idToIP[key] = ip
|
|
}
|
|
|
|
func (c *connections) getPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
|
|
peer, exists := c.idToPeerID[id.Key()]
|
|
return peer, exists
|
|
}
|
|
|
|
func (c *connections) getID(peer salticidae.PeerID) (ids.ShortID, bool) {
|
|
id, exists := c.peerIDToID[toID(peer)]
|
|
return id, exists
|
|
}
|
|
|
|
func (c *connections) remove(peer salticidae.PeerID, id ids.ShortID) {
|
|
c.removePeerID(peer)
|
|
c.removeID(id)
|
|
}
|
|
|
|
func (c *connections) removePeerID(peer salticidae.PeerID) {
|
|
peerID := toID(peer)
|
|
if id, exists := c.peerIDToID[peerID]; exists {
|
|
idKey := id.Key()
|
|
|
|
delete(c.peerIDToID, peerID)
|
|
delete(c.idToPeerID, idKey)
|
|
delete(c.idToIP, idKey)
|
|
}
|
|
}
|
|
|
|
func (c *connections) removeID(id ids.ShortID) {
|
|
idKey := id.Key()
|
|
if peer, exists := c.idToPeerID[idKey]; exists {
|
|
delete(c.peerIDToID, toID(peer))
|
|
delete(c.idToPeerID, idKey)
|
|
delete(c.idToIP, idKey)
|
|
}
|
|
}
|
|
|
|
func (c *connections) peerIDs() []salticidae.PeerID {
|
|
peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
|
|
for _, peer := range c.idToPeerID {
|
|
peers = append(peers, peer)
|
|
}
|
|
return peers
|
|
}
|
|
|
|
func (c *connections) ids() ids.ShortSet {
|
|
ids := ids.ShortSet{}
|
|
for _, id := range c.peerIDToID {
|
|
ids.Add(id)
|
|
}
|
|
return ids
|
|
}
|
|
|
|
func (c *connections) ips() []utils.IPDesc {
|
|
ips := make([]utils.IPDesc, 0, len(c.idToIP))
|
|
for _, ip := range c.idToIP {
|
|
ips = append(ips, ip)
|
|
}
|
|
return ips
|
|
}
|
|
|
|
func (c *connections) conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
|
|
peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
|
|
idList := make([]ids.ShortID, 0, len(c.idToPeerID))
|
|
ips := make([]utils.IPDesc, 0, len(c.idToPeerID))
|
|
for id, peer := range c.idToPeerID {
|
|
idList = append(idList, ids.NewShortID(id))
|
|
peers = append(peers, peer)
|
|
ips = append(ips, c.idToIP[id])
|
|
}
|
|
return peers, idList, ips
|
|
}
|
|
|
|
func (c *connections) len() int { return len(c.idToPeerID) }
|
|
|
|
func toID(peer salticidae.PeerID) [32]byte {
|
|
ds := salticidae.NewDataStream(false)
|
|
|
|
peerInt := peer.AsUInt256()
|
|
peerInt.Serialize(ds)
|
|
|
|
size := ds.Size()
|
|
dsb := ds.GetDataInPlace(size)
|
|
idBytes := dsb.Get()
|
|
|
|
id := [32]byte{}
|
|
copy(id[:], idBytes)
|
|
|
|
ds.Free()
|
|
return id
|
|
}
|
|
|
|
func toIPDesc(addr salticidae.NetAddr) utils.IPDesc {
|
|
ip, err := ToIPDesc(addr)
|
|
HandshakeNet.log.AssertNoError(err)
|
|
return ip
|
|
}
|
|
|
|
// ToIPDesc converts an address to an IP
|
|
func ToIPDesc(addr salticidae.NetAddr) (utils.IPDesc, error) {
|
|
ip := salticidae.FromBigEndianU32(addr.GetIP())
|
|
port := salticidae.FromBigEndianU16(addr.GetPort())
|
|
return utils.ToIPDesc(fmt.Sprintf("%d.%d.%d.%d:%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip), port))
|
|
}
|