Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/event/reachability.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ type EvtLocalReachabilityChanged struct {
}

// EvtHostReachableAddrsChanged is sent when host's reachable or unreachable addresses change
// Reachable and Unreachable both contain only Public IP or DNS addresses
// Reachable, Unreachable, and Unknown only contain Public IP or DNS addresses
//
// Experimental: This API is unstable. Any changes to this event will be done without a deprecation notice.
type EvtHostReachableAddrsChanged struct {
Reachable []ma.Multiaddr
Unreachable []ma.Multiaddr
Unknown []ma.Multiaddr
}
23 changes: 14 additions & 9 deletions p2p/host/basic/addrs_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type hostAddrs struct {
localAddrs []ma.Multiaddr
reachableAddrs []ma.Multiaddr
unreachableAddrs []ma.Multiaddr
unknownAddrs []ma.Multiaddr
relayAddrs []ma.Multiaddr
}

Expand Down Expand Up @@ -250,9 +251,9 @@ func (a *addrsManager) updateAddrs(updateRelayAddrs bool, relayAddrs []ma.Multia
defer a.addrsMx.Unlock()

localAddrs := a.getLocalAddrs()
var currReachableAddrs, currUnreachableAddrs []ma.Multiaddr
var currReachableAddrs, currUnreachableAddrs, currUnknownAddrs []ma.Multiaddr
if a.addrsReachabilityTracker != nil {
currReachableAddrs, currUnreachableAddrs = a.getConfirmedAddrs(localAddrs)
currReachableAddrs, currUnreachableAddrs, currUnknownAddrs = a.getConfirmedAddrs(localAddrs)
}
if !updateRelayAddrs {
relayAddrs = a.currentAddrs.relayAddrs
Expand All @@ -267,6 +268,7 @@ func (a *addrsManager) updateAddrs(updateRelayAddrs bool, relayAddrs []ma.Multia
localAddrs: append(a.currentAddrs.localAddrs[:0], localAddrs...),
reachableAddrs: append(a.currentAddrs.reachableAddrs[:0], currReachableAddrs...),
unreachableAddrs: append(a.currentAddrs.unreachableAddrs[:0], currUnreachableAddrs...),
unknownAddrs: append(a.currentAddrs.unknownAddrs[:0], currUnknownAddrs...),
relayAddrs: append(a.currentAddrs.relayAddrs[:0], relayAddrs...),
}

Expand All @@ -275,6 +277,7 @@ func (a *addrsManager) updateAddrs(updateRelayAddrs bool, relayAddrs []ma.Multia
addrs: currAddrs,
reachableAddrs: currReachableAddrs,
unreachableAddrs: currUnreachableAddrs,
unknownAddrs: currUnknownAddrs,
relayAddrs: relayAddrs,
}
}
Expand Down Expand Up @@ -303,11 +306,13 @@ func (a *addrsManager) notifyAddrsChanged(emitter event.Emitter, previous, curre
// We must send these events in the same order. It'll be confusing for consumers
// if the reachable event is received after the addr removed event.
if areAddrsDifferent(previous.reachableAddrs, current.reachableAddrs) ||
areAddrsDifferent(previous.unreachableAddrs, current.unreachableAddrs) {
areAddrsDifferent(previous.unreachableAddrs, current.unreachableAddrs) ||
areAddrsDifferent(previous.unknownAddrs, current.unknownAddrs) {
log.Debugf("host reachable addrs updated: %s", current.localAddrs)
if err := emitter.Emit(event.EvtHostReachableAddrsChanged{
Reachable: slices.Clone(current.reachableAddrs),
Unreachable: slices.Clone(current.unreachableAddrs),
Unknown: slices.Clone(current.unknownAddrs),
}); err != nil {
log.Errorf("error sending host reachable addrs changed event: %s", err)
}
Expand Down Expand Up @@ -365,16 +370,16 @@ func (a *addrsManager) DirectAddrs() []ma.Multiaddr {
return slices.Clone(a.currentAddrs.localAddrs)
}

// ReachableAddrs returns all addresses of the host that are reachable from the internet
func (a *addrsManager) ReachableAddrs() []ma.Multiaddr {
// ConfirmedAddrs returns all addresses of the host that are reachable from the internet
func (a *addrsManager) ConfirmedAddrs() (reachable []ma.Multiaddr, unreachable []ma.Multiaddr, unknown []ma.Multiaddr) {
a.addrsMx.RLock()
defer a.addrsMx.RUnlock()
return slices.Clone(a.currentAddrs.reachableAddrs)
return slices.Clone(a.currentAddrs.reachableAddrs), slices.Clone(a.currentAddrs.unreachableAddrs), slices.Clone(a.currentAddrs.unknownAddrs)
}

func (a *addrsManager) getConfirmedAddrs(localAddrs []ma.Multiaddr) (reachableAddrs, unreachableAddrs []ma.Multiaddr) {
reachableAddrs, unreachableAddrs = a.addrsReachabilityTracker.ConfirmedAddrs()
return removeNotInSource(reachableAddrs, localAddrs), removeNotInSource(unreachableAddrs, localAddrs)
func (a *addrsManager) getConfirmedAddrs(localAddrs []ma.Multiaddr) (reachableAddrs, unreachableAddrs, unknownAddrs []ma.Multiaddr) {
reachableAddrs, unreachableAddrs, unknownAddrs = a.addrsReachabilityTracker.ConfirmedAddrs()
return removeNotInSource(reachableAddrs, localAddrs), removeNotInSource(unreachableAddrs, localAddrs), removeNotInSource(unknownAddrs, localAddrs)
}

var p2pCircuitAddr = ma.StringCast("/p2p-circuit")
Expand Down
22 changes: 20 additions & 2 deletions p2p/host/basic/addrs_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,16 +462,34 @@ func TestAddrsManagerReachabilityEvent(t *testing.T) {
},
})

initialUnknownAddrs := []ma.Multiaddr{publicQUIC, publicTCP, publicQUIC2}

// First event: all addresses are initially unknown
select {
case e := <-sub.Out():
evt := e.(event.EvtHostReachableAddrsChanged)
require.Empty(t, evt.Reachable)
require.Empty(t, evt.Unreachable)
require.ElementsMatch(t, initialUnknownAddrs, evt.Unknown)
case <-time.After(5 * time.Second):
t.Fatal("expected initial event for reachability change")
}

// Wait for probes to complete and addresses to be classified
reachableAddrs := []ma.Multiaddr{publicQUIC}
unreachableAddrs := []ma.Multiaddr{publicTCP, publicQUIC2}
select {
case e := <-sub.Out():
evt := e.(event.EvtHostReachableAddrsChanged)
require.ElementsMatch(t, reachableAddrs, evt.Reachable)
require.ElementsMatch(t, unreachableAddrs, evt.Unreachable)
require.ElementsMatch(t, reachableAddrs, am.ReachableAddrs())
require.Empty(t, evt.Unknown)
reachable, unreachable, unknown := am.ConfirmedAddrs()
require.ElementsMatch(t, reachable, reachableAddrs)
require.ElementsMatch(t, unreachable, unreachableAddrs)
require.Empty(t, unknown)
case <-time.After(5 * time.Second):
t.Fatal("expected event for reachability change")
t.Fatal("expected final event for reachability change after probing")
}
}

Expand Down
25 changes: 15 additions & 10 deletions p2p/host/basic/addrs_reachability_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type addrsReachabilityTracker struct {
mx sync.Mutex
reachableAddrs []ma.Multiaddr
unreachableAddrs []ma.Multiaddr
unknownAddrs []ma.Multiaddr
}

// newAddrsReachabilityTracker returns a new addrsReachabilityTracker.
Expand Down Expand Up @@ -83,10 +84,10 @@ func (r *addrsReachabilityTracker) UpdateAddrs(addrs []ma.Multiaddr) {
}
}

func (r *addrsReachabilityTracker) ConfirmedAddrs() (reachableAddrs, unreachableAddrs []ma.Multiaddr) {
func (r *addrsReachabilityTracker) ConfirmedAddrs() (reachableAddrs, unreachableAddrs, unknownAddrs []ma.Multiaddr) {
r.mx.Lock()
defer r.mx.Unlock()
return slices.Clone(r.reachableAddrs), slices.Clone(r.unreachableAddrs)
return slices.Clone(r.reachableAddrs), slices.Clone(r.unreachableAddrs), slices.Clone(r.unknownAddrs)
}

func (r *addrsReachabilityTracker) Start() error {
Expand Down Expand Up @@ -129,7 +130,7 @@ func (r *addrsReachabilityTracker) background() {

var task reachabilityTask
var backoffInterval time.Duration
var currReachable, currUnreachable, prevReachable, prevUnreachable []ma.Multiaddr
var currReachable, currUnreachable, currUnknown, prevReachable, prevUnreachable, prevUnknown []ma.Multiaddr
for {
select {
case <-probeTicker.C:
Expand Down Expand Up @@ -173,12 +174,13 @@ func (r *addrsReachabilityTracker) background() {
return
}

currReachable, currUnreachable = r.appendConfirmedAddrs(currReachable[:0], currUnreachable[:0])
if areAddrsDifferent(prevReachable, currReachable) || areAddrsDifferent(prevUnreachable, currUnreachable) {
currReachable, currUnreachable, currUnknown = r.appendConfirmedAddrs(currReachable[:0], currUnreachable[:0], currUnknown[:0])
if areAddrsDifferent(prevReachable, currReachable) || areAddrsDifferent(prevUnreachable, currUnreachable) || areAddrsDifferent(prevUnknown, currUnknown) {
r.notify()
}
prevReachable = append(prevReachable[:0], currReachable...)
prevUnreachable = append(prevUnreachable[:0], currUnreachable...)
prevUnknown = append(prevUnknown[:0], currUnknown...)
if !nextProbeTime.IsZero() {
probeTimer.Reset(nextProbeTime.Sub(r.clock.Now()))
}
Expand All @@ -196,13 +198,14 @@ func newBackoffInterval(current time.Duration) time.Duration {
return current
}

func (r *addrsReachabilityTracker) appendConfirmedAddrs(reachable, unreachable []ma.Multiaddr) (reachableAddrs, unreachableAddrs []ma.Multiaddr) {
reachable, unreachable = r.probeManager.AppendConfirmedAddrs(reachable, unreachable)
func (r *addrsReachabilityTracker) appendConfirmedAddrs(reachable, unreachable, unknown []ma.Multiaddr) (reachableAddrs, unreachableAddrs, unknownAddrs []ma.Multiaddr) {
reachable, unreachable, unknown = r.probeManager.AppendConfirmedAddrs(reachable, unreachable, unknown)
r.mx.Lock()
r.reachableAddrs = append(r.reachableAddrs[:0], reachable...)
r.unreachableAddrs = append(r.unreachableAddrs[:0], unreachable...)
r.unknownAddrs = append(r.unknownAddrs[:0], unknown...)
r.mx.Unlock()
return reachable, unreachable
return reachable, unreachable, unknown
}

func (r *addrsReachabilityTracker) notify() {
Expand Down Expand Up @@ -381,7 +384,7 @@ func newProbeManager(now func() time.Time) *probeManager {
}

// AppendConfirmedAddrs appends the current confirmed reachable and unreachable addresses.
func (m *probeManager) AppendConfirmedAddrs(reachable, unreachable []ma.Multiaddr) (reachableAddrs, unreachableAddrs []ma.Multiaddr) {
func (m *probeManager) AppendConfirmedAddrs(reachable, unreachable, unknown []ma.Multiaddr) (reachableAddrs, unreachableAddrs, unknownAddrs []ma.Multiaddr) {
m.mx.Lock()
defer m.mx.Unlock()

Expand All @@ -393,9 +396,11 @@ func (m *probeManager) AppendConfirmedAddrs(reachable, unreachable []ma.Multiadd
reachable = append(reachable, a)
case network.ReachabilityPrivate:
unreachable = append(unreachable, a)
case network.ReachabilityUnknown:
unknown = append(unknown, a)
}
}
return reachable, unreachable
return reachable, unreachable, unknown
}

// UpdateAddrs updates the tracked addrs
Expand Down
Loading