Dmitry eeca435064 Add rendezvous implementation for discovery interface
Update vendor

Integrate rendezvous into status node

Add a test with failover using rendezvous

Use multiple servers in client

Use discovery V5 by default and test that node can be started with rendezvous discovet

Fix linter

Update rendezvous client to one with instrumented stream

Address feedback

Fix test with updated topic limits

Apply several suggestions

Change log to debug for request errors because we continue execution

Remove web3js after rebase

Update rendezvous package
2018-07-25 15:10:57 +03:00

144 lines
2.8 KiB
Go

package nat
import (
"fmt"
"sync"
"time"
"github.com/jbenet/goprocess"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net"
)
// Mapping represents a port mapping in a NAT.
type Mapping interface {
// NAT returns the NAT object this Mapping belongs to.
NAT() *NAT
// Protocol returns the protocol of this port mapping. This is either
// "tcp" or "udp" as no other protocols are likely to be NAT-supported.
Protocol() string
// InternalPort returns the internal device port. Mapping will continue to
// try to map InternalPort() to an external facing port.
InternalPort() int
// ExternalPort returns the external facing port. If the mapping is not
// established, port will be 0
ExternalPort() int
// InternalAddr returns the internal address.
InternalAddr() ma.Multiaddr
// ExternalAddr returns the external facing address. If the mapping is not
// established, addr will be nil, and and ErrNoMapping will be returned.
ExternalAddr() (addr ma.Multiaddr, err error)
// Close closes the port mapping
Close() error
}
// keeps republishing
type mapping struct {
sync.Mutex // guards all fields
nat *NAT
proto string
intport int
extport int
permanent bool
intaddr ma.Multiaddr
proc goprocess.Process
comment string
cached ma.Multiaddr
cacheTime time.Time
cacheLk sync.Mutex
}
func (m *mapping) NAT() *NAT {
m.Lock()
defer m.Unlock()
return m.nat
}
func (m *mapping) Protocol() string {
m.Lock()
defer m.Unlock()
return m.proto
}
func (m *mapping) InternalPort() int {
m.Lock()
defer m.Unlock()
return m.intport
}
func (m *mapping) ExternalPort() int {
m.Lock()
defer m.Unlock()
return m.extport
}
func (m *mapping) setExternalPort(p int) {
m.Lock()
defer m.Unlock()
m.extport = p
}
func (m *mapping) InternalAddr() ma.Multiaddr {
m.Lock()
defer m.Unlock()
return m.intaddr
}
func (m *mapping) ExternalAddr() (ma.Multiaddr, error) {
m.cacheLk.Lock()
ctime := m.cacheTime
cval := m.cached
m.cacheLk.Unlock()
if time.Since(ctime) < CacheTime {
return cval, nil
}
if m.ExternalPort() == 0 { // dont even try right now.
return nil, ErrNoMapping
}
m.nat.natmu.Lock()
ip, err := m.nat.nat.GetExternalAddress()
m.nat.natmu.Unlock()
if err != nil {
return nil, err
}
ipmaddr, err := manet.FromIP(ip)
if err != nil {
return nil, fmt.Errorf("error parsing ip")
}
// call m.ExternalPort again, as mapping may have changed under our feet. (tocttou)
extport := m.ExternalPort()
if extport == 0 {
return nil, ErrNoMapping
}
tcp, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%d", m.Protocol(), extport))
if err != nil {
return nil, err
}
maddr2 := ipmaddr.Encapsulate(tcp)
m.cacheLk.Lock()
m.cached = maddr2
m.cacheTime = time.Now()
m.cacheLk.Unlock()
return maddr2, nil
}
func (m *mapping) Close() error {
return m.proc.Close()
}