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

Loading…
Cancel
Save