diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index aa060d3335..053eec17f5 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -35,9 +35,8 @@ import ( const ( soapRequestTimeout = 3 * time.Second rateLimit = 200 * time.Millisecond - retryInterval = 1 * time.Second // time to wait between retries - retryCount = 3 // number of retries after a failed AddPortMapping - randomCount = 3 // number of random ports to try + retryCount = 3 // number of retries after a failed AddPortMapping + randomCount = 3 // number of random ports to try ) type upnp struct { @@ -101,30 +100,26 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li } // Try to add port mapping, preferring the specified external port. - err = n.withRateLimit(func() error { - p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) - if err == nil { - extport = int(p) - } - return err - }) - return uint16(extport), err + return n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) } // addAnyPortMapping tries to add a port mapping with the specified external port. // If the external port is already in use, it will try to assign another port. func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) { if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok { - return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + return n.portWithRateLimit(func() (uint16, error) { + return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) } // For IGDv1 and v1 services we should first try to add with extport. for i := 0; i < retryCount+1; i++ { - err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + err := n.withRateLimit(func() error { + return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) if err == nil { return uint16(extport), nil } log.Trace("Failed to add port mapping", "protocol", protocol, "extport", extport, "intport", intport, "err", err) - time.Sleep(retryInterval) } // If above fails, we retry with a random port. @@ -132,12 +127,13 @@ func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.I var err error for i := 0; i < randomCount; i++ { extport = n.randomPort() - err = n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + err := n.withRateLimit(func() error { + return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) if err == nil { return uint16(extport), nil } log.Trace("Failed to add random port mapping", "protocol", protocol, "extport", extport, "intport", intport, "err", err) - time.Sleep(retryInterval) } return 0, err } @@ -182,6 +178,17 @@ func (n *upnp) String() string { return "UPNP " + n.service } +func (n *upnp) portWithRateLimit(pfn func() (uint16, error)) (uint16, error) { + var port uint16 + var err error + fn := func() error { + port, err = pfn() + return err + } + n.withRateLimit(fn) + return port, err +} + func (n *upnp) withRateLimit(fn func() error) error { n.mu.Lock() defer n.mu.Unlock()