Skip to content
Snippets Groups Projects
Unverified Commit cae647a5 authored by Wolfgang Welz's avatar Wolfgang Welz Committed by GitHub
Browse files

Fix: Only connect to valid neighbors (#182)

parent 3b62158d
Branches
Tags
No related merge requests found
...@@ -3,7 +3,7 @@ package selection ...@@ -3,7 +3,7 @@ package selection
import ( import (
"time" "time"
"github.com/iotaledger/goshimmer/packages/autopeering/peer/service" "github.com/iotaledger/goshimmer/packages/autopeering/peer"
"github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/logger"
) )
...@@ -30,10 +30,22 @@ type Config struct { ...@@ -30,10 +30,22 @@ type Config struct {
Log *logger.Logger Log *logger.Logger
// These settings are optional: // These settings are optional:
DropOnUpdate bool // set true to drop all neighbors when the salt is updated DropOnUpdate bool // set true to drop all neighbors when the salt is updated
RequiredServices []service.Key // services required in order to select/be selected during autopeering NeighborValidator Validator // potential neighbor validator
} }
// A Validator checks whether a peer is a valid neighbor
type Validator interface {
IsValid(*peer.Peer) bool
}
// The ValidatorFunc type is an adapter to allow the use of ordinary functions as neighbor validators.
// If f is a function with the appropriate signature, ValidatorFunc(f) is a Validator that calls f.
type ValidatorFunc func(p *peer.Peer) bool
// IsValid calls f(p).
func (f ValidatorFunc) IsValid(p *peer.Peer) bool { return f(p) }
// Parameters holds the parameters that can be configured. // Parameters holds the parameters that can be configured.
type Parameters struct { type Parameters struct {
InboundNeighborSize int // number of inbound neighbors InboundNeighborSize int // number of inbound neighbors
......
...@@ -5,7 +5,6 @@ import ( ...@@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/iotaledger/goshimmer/packages/autopeering/peer" "github.com/iotaledger/goshimmer/packages/autopeering/peer"
"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
"github.com/iotaledger/goshimmer/packages/autopeering/salt" "github.com/iotaledger/goshimmer/packages/autopeering/salt"
"github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/logger"
) )
...@@ -35,8 +34,8 @@ type manager struct { ...@@ -35,8 +34,8 @@ type manager struct {
net network net network
getPeersToConnect func() []*peer.Peer getPeersToConnect func() []*peer.Peer
log *logger.Logger log *logger.Logger
dropOnUpdate bool // set true to drop all neighbors when the salt is updated dropOnUpdate bool // set true to drop all neighbors when the salt is updated
requiredServices []service.Key // services required in order to select/be selected during autopeering neighborValidator Validator // potential neighbor validator
inbound *Neighborhood inbound *Neighborhood
outbound *Neighborhood outbound *Neighborhood
...@@ -57,7 +56,7 @@ func newManager(net network, peersFunc func() []*peer.Peer, log *logger.Logger, ...@@ -57,7 +56,7 @@ func newManager(net network, peersFunc func() []*peer.Peer, log *logger.Logger,
getPeersToConnect: peersFunc, getPeersToConnect: peersFunc,
log: log, log: log,
dropOnUpdate: config.DropOnUpdate, dropOnUpdate: config.DropOnUpdate,
requiredServices: config.RequiredServices, neighborValidator: config.NeighborValidator,
inbound: NewNeighborhood(inboundNeighborSize), inbound: NewNeighborhood(inboundNeighborSize),
outbound: NewNeighborhood(outboundNeighborSize), outbound: NewNeighborhood(outboundNeighborSize),
rejectionFilter: NewFilter(), rejectionFilter: NewFilter(),
...@@ -217,9 +216,12 @@ func (m *manager) updateOutbound(resultChan chan<- peer.PeerDistance) { ...@@ -217,9 +216,12 @@ func (m *manager) updateOutbound(resultChan chan<- peer.PeerDistance) {
// filter out current neighbors // filter out current neighbors
filter := m.getConnectedFilter() filter := m.getConnectedFilter()
filteredList := filter.Apply(distList) if m.neighborValidator != nil {
filter.AddCondition(m.neighborValidator.IsValid)
}
// filter out previous rejections // filter out previous rejections
filteredList = m.rejectionFilter.Apply(filteredList) filteredList := m.rejectionFilter.Apply(filter.Apply(distList))
if len(filteredList) == 0 { if len(filteredList) == 0 {
return return
} }
...@@ -340,13 +342,10 @@ func (m *manager) isValidNeighbor(p *peer.Peer) bool { ...@@ -340,13 +342,10 @@ func (m *manager) isValidNeighbor(p *peer.Peer) bool {
if m.getID() == p.ID() { if m.getID() == p.ID() {
return false return false
} }
// reject if required services are missing if m.neighborValidator == nil {
for _, reqService := range m.requiredServices { return true
if p.Services().Get(reqService) == nil {
return false
}
} }
return true return m.neighborValidator.IsValid(p)
} }
func (m *manager) triggerPeeringEvent(isOut bool, p *peer.Peer, status bool) { func (m *manager) triggerPeeringEvent(isOut bool, p *peer.Peer, status bool) {
......
...@@ -11,8 +11,9 @@ type Selector interface { ...@@ -11,8 +11,9 @@ type Selector interface {
} }
type Filter struct { type Filter struct {
internal map[peer.ID]bool internal map[peer.ID]bool
lock sync.RWMutex conditions []func(*peer.Peer) bool
lock sync.RWMutex
} }
func NewFilter() *Filter { func NewFilter() *Filter {
...@@ -21,29 +22,23 @@ func NewFilter() *Filter { ...@@ -21,29 +22,23 @@ func NewFilter() *Filter {
} }
} }
func (f *Filter) Apply(list []peer.PeerDistance) (filteredList []peer.PeerDistance) { func (f *Filter) Apply(list []peer.PeerDistance) (filtered []peer.PeerDistance) {
f.lock.RLock() f.lock.RLock()
defer f.lock.RUnlock() defer f.lock.RUnlock()
for _, p := range list {
if !f.internal[p.Remote.ID()] {
filteredList = append(filteredList, p)
}
}
return filteredList
}
func (f *Filter) PushBack(list []peer.PeerDistance) (filteredList []peer.PeerDistance) { list:
var head, tail []peer.PeerDistance
f.lock.RLock()
defer f.lock.RUnlock()
for _, p := range list { for _, p := range list {
if f.internal[p.Remote.ID()] { if _, contains := f.internal[p.Remote.ID()]; contains {
tail = append(tail, p) continue
} else { }
head = append(head, p) for _, c := range f.conditions {
if !c(p.Remote) {
continue list
}
} }
filtered = append(filtered, p)
} }
return append(head, tail...) return
} }
func (f *Filter) AddPeers(n []*peer.Peer) { func (f *Filter) AddPeers(n []*peer.Peer) {
...@@ -66,6 +61,10 @@ func (f *Filter) RemovePeer(peer peer.ID) { ...@@ -66,6 +61,10 @@ func (f *Filter) RemovePeer(peer peer.ID) {
f.lock.Unlock() f.lock.Unlock()
} }
func (f *Filter) AddCondition(c func(p *peer.Peer) bool) {
f.conditions = append(f.conditions, c)
}
func (f *Filter) Clean() { func (f *Filter) Clean() {
f.lock.Lock() f.lock.Lock()
f.internal = make(map[peer.ID]bool) f.internal = make(map[peer.ID]bool)
......
...@@ -48,12 +48,32 @@ func configureAP() { ...@@ -48,12 +48,32 @@ func configureAP() {
// enable peer selection only when gossip is enabled // enable peer selection only when gossip is enabled
if !node.IsSkipped(gossip.PLUGIN) { if !node.IsSkipped(gossip.PLUGIN) {
Selection = selection.New(local.GetInstance(), Discovery, selection.Config{ Selection = selection.New(local.GetInstance(), Discovery, selection.Config{
Log: log.Named("sel"), Log: log.Named("sel"),
RequiredServices: []service.Key{service.GossipKey}, NeighborValidator: selection.ValidatorFunc(isValidNeighbor),
}) })
} }
} }
// isValidNeighbor checks whether a peer is a valid neighbor.
func isValidNeighbor(p *peer.Peer) bool {
// gossip must be supported
gossipAddr := p.Services().Get(service.GossipKey)
if gossipAddr == nil {
return false
}
// the host for the gossip and peering service must be identical
gossipHost, _, err := net.SplitHostPort(gossipAddr.String())
if err != nil {
return false
}
peeringAddr := p.Services().Get(service.PeeringKey)
peeringHost, _, err := net.SplitHostPort(peeringAddr.String())
if err != nil {
return false
}
return gossipHost == peeringHost
}
func start(shutdownSignal <-chan struct{}) { func start(shutdownSignal <-chan struct{}) {
defer log.Info("Stopping " + name + " ... done") defer log.Info("Stopping " + name + " ... done")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment