Browse Source

compute relay address set dynamically

pull/598/head
vyzo 6 years ago
parent
commit
c09717275b
  1. 117
      p2p/host/relay/autorelay.go

117
p2p/host/relay/autorelay.go

@ -42,7 +42,7 @@ type AutoRelay struct {
mx sync.Mutex mx sync.Mutex
relays map[peer.ID]struct{} 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 { 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, addrsF: bhost.AddrsFactory,
relays: make(map[peer.ID]struct{}), relays: make(map[peer.ID]struct{}),
disconnect: make(chan struct{}, 1), disconnect: make(chan struct{}, 1),
status: autonat.NATStatusUnknown,
} }
ar.autonat = autonat.NewAutoNAT(ctx, bhost, ar.baseAddrs) ar.autonat = autonat.NewAutoNAT(ctx, bhost, ar.baseAddrs)
bhost.AddrsFactory = ar.hostAddrs bhost.AddrsFactory = ar.hostAddrs
@ -61,20 +62,14 @@ func NewAutoRelay(ctx context.Context, bhost *basic.BasicHost, discover discover
return ar 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 { func (ar *AutoRelay) baseAddrs() []ma.Multiaddr {
return ar.addrsF(ar.host.AllAddrs()) 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) { func (ar *AutoRelay) background(ctx context.Context) {
select { select {
case <-time.After(autonat.AutoNATBootDelay + BootDelay): case <-time.After(autonat.AutoNATBootDelay + BootDelay):
@ -89,37 +84,37 @@ func (ar *AutoRelay) background(ctx context.Context) {
wait := autonat.AutoNATRefreshInterval wait := autonat.AutoNATRefreshInterval
switch ar.autonat.Status() { switch ar.autonat.Status() {
case autonat.NATStatusUnknown: case autonat.NATStatusUnknown:
ar.mx.Lock()
ar.status = autonat.NATStatusUnknown
ar.mx.Unlock()
wait = autonat.AutoNATRetryInterval wait = autonat.AutoNATRetryInterval
case autonat.NATStatusPublic: case autonat.NATStatusPublic:
// invalidate addrs
ar.mx.Lock() ar.mx.Lock()
if ar.addrs != nil { if ar.status != autonat.NATStatusPublic {
ar.addrs = nil
push = true push = true
} }
ar.status = autonat.NATStatusPublic
ar.mx.Unlock() ar.mx.Unlock()
// if we had previously announced relay addrs, push our public addrs case autonat.NATStatusPrivate:
if push { update := ar.findRelays(ctx)
push = false ar.mx.Lock()
ar.host.PushIdentify() if update || ar.status != autonat.NATStatusPrivate {
push = true
} }
ar.status = autonat.NATStatusPrivate
ar.mx.Unlock()
}
case autonat.NATStatusPrivate: if push {
push = false // clear, findRelays pushes as needed push = false
ar.findRelays(ctx) ar.host.PushIdentify()
} }
select { select {
case <-ar.disconnect: case <-ar.disconnect:
// invalidate addrs push = true
ar.mx.Lock()
if ar.addrs != nil {
ar.addrs = nil
push = true
}
ar.mx.Unlock()
case <-time.After(wait): case <-time.After(wait):
case <-ctx.Done(): case <-ctx.Done():
return 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: again:
ar.mx.Lock() ar.mx.Lock()
haveRelays := len(ar.relays) haveRelays := len(ar.relays)
if haveRelays >= DesiredRelays { if haveRelays >= DesiredRelays {
ar.mx.Unlock() ar.mx.Unlock()
// this dance is necessary to cover the Private->Public->Private transition return false
// 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
} }
need := DesiredRelays - len(ar.relays) need := DesiredRelays - len(ar.relays)
ar.mx.Unlock() ar.mx.Unlock()
@ -153,7 +140,16 @@ again:
cancel() cancel()
if err != nil { if err != nil {
log.Debugf("error discovering relays: %s", err.Error()) 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)) log.Debugf("discovered %d relays", len(pis))
@ -201,13 +197,11 @@ again:
case <-time.After(30 * time.Second): case <-time.After(30 * time.Second):
goto again goto again
case <-ctx.Done(): case <-ctx.Done():
return return false
} }
} }
if update > 0 || ar.addrs == nil { return update > 0
ar.updateAddrs()
}
} }
func (ar *AutoRelay) selectRelays(ctx context.Context, pis []pstore.PeerInfo, count, maxq int) []pstore.PeerInfo { 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 return result
} }
func (ar *AutoRelay) updateAddrs() { // This function is computes the NATed relay addrs when our status is private:
ar.doUpdateAddrs() // - The public addrs are removed from the address set.
ar.host.PushIdentify() // - 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
// This function updates our NATed advertised addrs (ar.addrs) // connected. For each non-private relay addr, we encapsulate the p2p-circuit addr
// The public addrs are rewritten so that they only retain the public IP part; they // through which we can be dialed.
// become undialable but are useful as a hint to the dialer to determine whether or not func (ar *AutoRelay) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
// 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() {
ar.mx.Lock() ar.mx.Lock()
defer ar.mx.Unlock() defer ar.mx.Unlock()
addrs := ar.baseAddrs() if ar.status != autonat.NATStatusPrivate {
return addrs
}
raddrs := make([]ma.Multiaddr, 0, len(addrs)+len(ar.relays)) 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 { for _, addr := range addrs {
if manet.IsPublicAddr(addr) { if manet.IsPrivateAddr(addr) {
continue raddrs = append(raddrs, addr)
} }
raddrs = append(raddrs, addr)
} }
// add relay specific addrs to the list // 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) { func shuffleRelays(pis []pstore.PeerInfo) {

Loading…
Cancel
Save