mirror of https://github.com/poanetwork/gecko.git
144 lines
3.2 KiB
Go
144 lines
3.2 KiB
Go
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package nat
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/ava-labs/gecko/utils/logging"
|
|
"github.com/ava-labs/gecko/utils/wrappers"
|
|
)
|
|
|
|
const (
|
|
defaultMappingTimeout = 30 * time.Minute
|
|
defaultMappingUpdateInterval = 3 * defaultMappingTimeout / 4
|
|
)
|
|
|
|
// Mapper maps port
|
|
type Mapper interface {
|
|
MapPort(newInternalPort, newExternalPort uint16) error
|
|
UnmapAllPorts() error
|
|
}
|
|
|
|
type mapper struct {
|
|
log logging.Logger
|
|
router Router
|
|
networkProtocol NetworkProtocol
|
|
mappingNames string
|
|
mappingTimeout time.Duration
|
|
mappingUpdateInterval time.Duration
|
|
|
|
closer chan struct{}
|
|
wg sync.WaitGroup
|
|
errLock sync.Mutex
|
|
errs wrappers.Errs
|
|
}
|
|
|
|
// NewMapper returns a new mapper that can map ports on a router
|
|
func NewMapper(
|
|
log logging.Logger,
|
|
router Router,
|
|
networkProtocol NetworkProtocol,
|
|
mappingNames string,
|
|
mappingTimeout time.Duration,
|
|
mappingUpdateInterval time.Duration,
|
|
) Mapper {
|
|
return &mapper{
|
|
log: log,
|
|
router: router,
|
|
networkProtocol: networkProtocol,
|
|
mappingNames: mappingNames,
|
|
mappingTimeout: mappingTimeout,
|
|
mappingUpdateInterval: mappingUpdateInterval,
|
|
closer: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// NewDefaultMapper returns a new mapper that can map ports on a router with
|
|
// default settings
|
|
func NewDefaultMapper(
|
|
log logging.Logger,
|
|
router Router,
|
|
networkProtocol NetworkProtocol,
|
|
mappingNames string,
|
|
) Mapper {
|
|
return NewMapper(
|
|
log,
|
|
router,
|
|
networkProtocol,
|
|
mappingNames,
|
|
defaultMappingTimeout, // uses the default value
|
|
defaultMappingUpdateInterval, // uses the default value
|
|
)
|
|
}
|
|
|
|
// MapPort maps a local port to a port on the router until UnmapAllPorts is
|
|
// called.
|
|
func (m *mapper) MapPort(newInternalPort, newExternalPort uint16) error {
|
|
m.wg.Add(1)
|
|
go m.mapPort(newInternalPort, newExternalPort)
|
|
return nil
|
|
}
|
|
|
|
func (m *mapper) mapPort(newInternalPort, newExternalPort uint16) {
|
|
// duration is set to 0 here so that the select case will execute
|
|
// immediately
|
|
updateTimer := time.NewTimer(0)
|
|
defer func() {
|
|
updateTimer.Stop()
|
|
|
|
m.errLock.Lock()
|
|
m.errs.Add(m.router.UnmapPort(
|
|
m.networkProtocol,
|
|
newInternalPort,
|
|
newExternalPort))
|
|
m.errLock.Unlock()
|
|
|
|
m.log.Debug("Unmapped external port %d to internal port %d",
|
|
newExternalPort,
|
|
newInternalPort)
|
|
|
|
m.wg.Done()
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-updateTimer.C:
|
|
err := m.router.MapPort(
|
|
m.networkProtocol,
|
|
newInternalPort,
|
|
newExternalPort,
|
|
m.mappingNames,
|
|
m.mappingTimeout)
|
|
|
|
if err != nil {
|
|
m.errLock.Lock()
|
|
m.errs.Add(err)
|
|
m.errLock.Unlock()
|
|
|
|
m.log.Debug("Failed to add mapping from external port %d to internal port %d due to %s",
|
|
newExternalPort,
|
|
newInternalPort,
|
|
err)
|
|
} else {
|
|
m.log.Debug("Mapped external port %d to internal port %d",
|
|
newExternalPort,
|
|
newInternalPort)
|
|
}
|
|
|
|
// remap the port in m.mappingUpdateInterval
|
|
updateTimer.Reset(m.mappingUpdateInterval)
|
|
case _, _ = <-m.closer:
|
|
return // only return when all ports are unmapped
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *mapper) UnmapAllPorts() error {
|
|
close(m.closer)
|
|
m.wg.Wait()
|
|
return m.errs.Err
|
|
}
|