From c09717275bf5ea10eceef25971769233b8087d0c Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 20 Apr 2019 00:54:44 +0300 Subject: [PATCH] compute relay address set dynamically --- p2p/host/relay/autorelay.go | 117 ++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 64 deletions(-) diff --git a/p2p/host/relay/autorelay.go b/p2p/host/relay/autorelay.go index 5a88f1541..dc811dd8c 100644 --- a/p2p/host/relay/autorelay.go +++ b/p2p/host/relay/autorelay.go @@ -42,7 +42,7 @@ type AutoRelay struct { mx sync.Mutex relays map[peer.ID]struct{} - addrs []ma.Multiaddr + status autonat.NATStatus } func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discovery.Discoverer, router routing.PeerRouting) *AutoRelay { @@ -53,6 +53,7 @@ func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discover addrsF: bhost.AddrsFactory, relays: make(map[peer.ID]struct{}), disconnect: make(chan struct{}, 1), + status: autonat.NATStatusUnknown, } ar.autonat = autonat.NewAutoNAT(ctx, bhost, ar.baseAddrs) bhost.AddrsFactory = ar.hostAddrs @@ -61,20 +62,14 @@ func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discover return ar } -func (ar *AutoRelay) hostAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { - ar.mx.Lock() - defer ar.mx.Unlock() - if ar.addrs != nil && ar.autonat.Status() == autonat.NATStatusPrivate { - return ar.addrs - } else { - return ar.addrsF(addrs) - } -} - func (ar *AutoRelay) baseAddrs() []ma.Multiaddr { return ar.addrsF(ar.host.AllAddrs()) } +func (ar *AutoRelay) hostAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { + return ar.relayAddrs(ar.addrsF(addrs)) +} + func (ar *AutoRelay) background(ctx context.Context) { select { case <-time.After(autonat.AutoNATBootDelay + BootDelay): @@ -89,37 +84,37 @@ func (ar *AutoRelay) background(ctx context.Context) { wait := autonat.AutoNATRefreshInterval switch ar.autonat.Status() { case autonat.NATStatusUnknown: + ar.mx.Lock() + ar.status = autonat.NATStatusUnknown + ar.mx.Unlock() wait = autonat.AutoNATRetryInterval case autonat.NATStatusPublic: - // invalidate addrs ar.mx.Lock() - if ar.addrs != nil { - ar.addrs = nil + if ar.status != autonat.NATStatusPublic { push = true } + ar.status = autonat.NATStatusPublic ar.mx.Unlock() - // if we had previously announced relay addrs, push our public addrs - if push { - push = false - ar.host.PushIdentify() + case autonat.NATStatusPrivate: + update := ar.findRelays(ctx) + ar.mx.Lock() + if update || ar.status != autonat.NATStatusPrivate { + push = true } + ar.status = autonat.NATStatusPrivate + ar.mx.Unlock() + } - case autonat.NATStatusPrivate: - push = false // clear, findRelays pushes as needed - ar.findRelays(ctx) + if push { + push = false + ar.host.PushIdentify() } select { case <-ar.disconnect: - // invalidate addrs - ar.mx.Lock() - if ar.addrs != nil { - ar.addrs = nil - push = true - } - ar.mx.Unlock() + push = true case <-time.After(wait): case <-ctx.Done(): return @@ -127,21 +122,13 @@ func (ar *AutoRelay) background(ctx context.Context) { } } -func (ar *AutoRelay) findRelays(ctx context.Context) { +func (ar *AutoRelay) findRelays(ctx context.Context) bool { again: ar.mx.Lock() haveRelays := len(ar.relays) if haveRelays >= DesiredRelays { ar.mx.Unlock() - // this dance is necessary to cover the Private->Public->Private transition - // where we were already connected to enough relays while private and dropped - // the addrs while public. - // Note tht we don't need the lock for reading addrs, as the only writer is - // the current goroutine. - if ar.addrs == nil { - ar.updateAddrs() - } - return + return false } need := DesiredRelays - len(ar.relays) ar.mx.Unlock() @@ -153,7 +140,16 @@ again: cancel() if err != nil { log.Debugf("error discovering relays: %s", err.Error()) - return + + if haveRelays == 0 { + log.Debug("no relays connected; retrying in 30s") + select { + case <-time.After(30 * time.Second): + goto again + case <-ctx.Done(): + return false + } + } } log.Debugf("discovered %d relays", len(pis)) @@ -201,13 +197,11 @@ again: case <-time.After(30 * time.Second): goto again case <-ctx.Done(): - return + return false } } - if update > 0 || ar.addrs == nil { - ar.updateAddrs() - } + return update > 0 } func (ar *AutoRelay) selectRelays(ctx context.Context, pis []pstore.PeerInfo, count, maxq int) []pstore.PeerInfo { @@ -273,33 +267,28 @@ func (ar *AutoRelay) selectRelays(ctx context.Context, pis []pstore.PeerInfo, co return result } -func (ar *AutoRelay) updateAddrs() { - ar.doUpdateAddrs() - ar.host.PushIdentify() -} - -// This function updates our NATed advertised addrs (ar.addrs) -// The public addrs are rewritten so that they only retain the public IP part; they -// become undialable but are useful as a hint to the dialer to determine whether or not -// to dial private addrs. -// The non-public addrs are included verbatim so that peers behind the same NAT/firewall -// can still dial us directly. -// On top of those, we add the relay-specific addrs for the relays to which we are -// connected. For each non-private relay addr, we encapsulate the p2p-circuit addr -// through which we can be dialed. -func (ar *AutoRelay) doUpdateAddrs() { +// This function is computes the NATed relay addrs when our status is private: +// - The public addrs are removed from the address set. +// - The non-public addrs are included verbatim so that peers behind the same NAT/firewall +// can still dial us directly. +// - On top of those, we add the relay-specific addrs for the relays to which we are +// connected. For each non-private relay addr, we encapsulate the p2p-circuit addr +// through which we can be dialed. +func (ar *AutoRelay) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { ar.mx.Lock() defer ar.mx.Unlock() - addrs := ar.baseAddrs() + if ar.status != autonat.NATStatusPrivate { + return addrs + } + raddrs := make([]ma.Multiaddr, 0, len(addrs)+len(ar.relays)) - // remove our public addresses from the list + // only keep private addrs from the original addr set for _, addr := range addrs { - if manet.IsPublicAddr(addr) { - continue + if manet.IsPrivateAddr(addr) { + raddrs = append(raddrs, addr) } - raddrs = append(raddrs, addr) } // add relay specific addrs to the list @@ -317,7 +306,7 @@ func (ar *AutoRelay) doUpdateAddrs() { } } - ar.addrs = raddrs + return raddrs } func shuffleRelays(pis []pstore.PeerInfo) {