parallelize dialbacks
@@ -32,7 +32,7 @@ var (
AutoNATBootDelay = 15 * time.Second
AutoNATRetryInterval = 90 * time.Second
AutoNATRefreshInterval = 15 * time.Minute
- AutoNATRequestTimeout = 60 * time.Second
+ AutoNATRequestTimeout = 30 * time.Second
)
// AutoNAT is the interface for ambient NAT autodiscovery
@@ -135,50 +135,74 @@ func (as *AmbientAutoNAT) autodetect() {
}
cli := NewAutoNATClient(as.host, as.getAddrs)
- failures := 0
-
- for _, pi := range peers {
ctx, cancel := context.WithTimeout(as.ctx, AutoNATRequestTimeout)
+ defer cancel()
+
+ var mx sync.Mutex
+ var pubaddr ma.Multiaddr
+ private := 0
+ public := 0
+
+ probe := 3 - as.confidence
+ if probe == 0 {
+ probe = 1
+ }
+ if probe > len(peers) {
+ probe = len(peers)
+ }
+
+ var wg sync.WaitGroup
+
+ for _, pi := range peers[:probe] {
+ wg.Add(1)
+ go func(pi pstore.PeerInfo) {
as.host.Peerstore().AddAddrs(pi.ID, pi.Addrs, pstore.TempAddrTTL)
a, err := cli.DialBack(ctx, pi.ID)
- cancel()
switch {
case err == nil:
- log.Debugf("NAT status is public; address through %s: %s", pi.ID.Pretty(), a.String())
- as.mx.Lock()
- as.addr = a
- as.status = NATStatusPublic
- as.confidence = 0
- as.mx.Unlock()
- return
+ log.Debugf("Dialback through %s successful; public address is %s", pi.ID.Pretty(), a.String())
+ mx.Lock()
+ public++
+ pubaddr = a
+ mx.Unlock()
case IsDialError(err):
- log.Debugf("dial error through %s: %s", pi.ID.Pretty(), err.Error())
- failures++
- if failures >= 3 || as.confidence >= 3 { // 3 times is enemy action
- log.Debugf("NAT status is private")
- as.mx.Lock()
- as.status = NATStatusPrivate
- as.confidence = 3
- as.mx.Unlock()
- return
- }
+ log.Debugf("Dialback through %s failed", pi.ID.Pretty())
+ mx.Lock()
+ private++
+ mx.Unlock()
default:
- log.Debugf("Error dialing through %s: %s", pi.ID.Pretty(), err.Error())
+ log.Debugf("Dialback error through %s: %s", pi.ID.Pretty(), err)
}
+
+ wg.Done()
+ }(pi)
}
+ wg.Wait()
+
as.mx.Lock()
- if failures > 0 {
- as.status = NATStatusPrivate
+ if public > 0 {
+ log.Debugf("NAT status is public")
+ as.status = NATStatusPublic
+ as.addr = pubaddr
+ if as.confidence < 3 {
as.confidence++
+ }
+ } else if private > 0 {
log.Debugf("NAT status is private")
+ as.status = NATStatusPrivate
+ as.addr = nil
+ if as.confidence < 3 {
+ as.confidence++
+ }
} else {
+ log.Debugf("NAT status is unknown")
as.status = NATStatusUnknown
+ as.addr = nil
as.confidence = 0
- log.Debugf("NAT status is unknown")
}
as.mx.Unlock()
}
