|
|
@ -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) { |
|
|
|