|
@@ -14,17 +14,21 @@ import (
|
|
|
stdsync "sync"
|
|
|
"time"
|
|
|
|
|
|
+ "github.com/thejerf/suture"
|
|
|
+
|
|
|
"github.com/syncthing/syncthing/lib/config"
|
|
|
"github.com/syncthing/syncthing/lib/protocol"
|
|
|
"github.com/syncthing/syncthing/lib/sync"
|
|
|
+ "github.com/syncthing/syncthing/lib/util"
|
|
|
)
|
|
|
|
|
|
// Service runs a loop for discovery of IGDs (Internet Gateway Devices) and
|
|
|
// setup/renewal of a port mapping.
|
|
|
type Service struct {
|
|
|
- id protocol.DeviceID
|
|
|
- cfg config.Wrapper
|
|
|
- stop chan struct{}
|
|
|
+ suture.Service
|
|
|
+
|
|
|
+ id protocol.DeviceID
|
|
|
+ cfg config.Wrapper
|
|
|
|
|
|
mappings []*Mapping
|
|
|
timer *time.Timer
|
|
@@ -32,27 +36,28 @@ type Service struct {
|
|
|
}
|
|
|
|
|
|
func NewService(id protocol.DeviceID, cfg config.Wrapper) *Service {
|
|
|
- return &Service{
|
|
|
+ s := &Service{
|
|
|
id: id,
|
|
|
cfg: cfg,
|
|
|
|
|
|
timer: time.NewTimer(0),
|
|
|
mut: sync.NewRWMutex(),
|
|
|
}
|
|
|
+ s.Service = util.AsService(s.serve)
|
|
|
+ return s
|
|
|
}
|
|
|
|
|
|
-func (s *Service) Serve() {
|
|
|
+func (s *Service) serve(stop chan struct{}) {
|
|
|
announce := stdsync.Once{}
|
|
|
|
|
|
s.mut.Lock()
|
|
|
s.timer.Reset(0)
|
|
|
- s.stop = make(chan struct{})
|
|
|
s.mut.Unlock()
|
|
|
|
|
|
for {
|
|
|
select {
|
|
|
case <-s.timer.C:
|
|
|
- if found := s.process(); found != -1 {
|
|
|
+ if found := s.process(stop); found != -1 {
|
|
|
announce.Do(func() {
|
|
|
suffix := "s"
|
|
|
if found == 1 {
|
|
@@ -61,7 +66,7 @@ func (s *Service) Serve() {
|
|
|
l.Infoln("Detected", found, "NAT service"+suffix)
|
|
|
})
|
|
|
}
|
|
|
- case <-s.stop:
|
|
|
+ case <-stop:
|
|
|
s.timer.Stop()
|
|
|
s.mut.RLock()
|
|
|
for _, mapping := range s.mappings {
|
|
@@ -73,7 +78,7 @@ func (s *Service) Serve() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (s *Service) process() int {
|
|
|
+func (s *Service) process(stop chan struct{}) int {
|
|
|
// toRenew are mappings which are due for renewal
|
|
|
// toUpdate are the remaining mappings, which will only be updated if one of
|
|
|
// the old IGDs has gone away, or a new IGD has appeared, but only if we
|
|
@@ -115,25 +120,19 @@ func (s *Service) process() int {
|
|
|
return -1
|
|
|
}
|
|
|
|
|
|
- nats := discoverAll(time.Duration(s.cfg.Options().NATRenewalM)*time.Minute, time.Duration(s.cfg.Options().NATTimeoutS)*time.Second)
|
|
|
+ nats := discoverAll(time.Duration(s.cfg.Options().NATRenewalM)*time.Minute, time.Duration(s.cfg.Options().NATTimeoutS)*time.Second, stop)
|
|
|
|
|
|
for _, mapping := range toRenew {
|
|
|
- s.updateMapping(mapping, nats, true)
|
|
|
+ s.updateMapping(mapping, nats, true, stop)
|
|
|
}
|
|
|
|
|
|
for _, mapping := range toUpdate {
|
|
|
- s.updateMapping(mapping, nats, false)
|
|
|
+ s.updateMapping(mapping, nats, false, stop)
|
|
|
}
|
|
|
|
|
|
return len(nats)
|
|
|
}
|
|
|
|
|
|
-func (s *Service) Stop() {
|
|
|
- s.mut.RLock()
|
|
|
- close(s.stop)
|
|
|
- s.mut.RUnlock()
|
|
|
-}
|
|
|
-
|
|
|
func (s *Service) NewMapping(protocol Protocol, ip net.IP, port int) *Mapping {
|
|
|
mapping := &Mapping{
|
|
|
protocol: protocol,
|
|
@@ -178,17 +177,17 @@ func (s *Service) RemoveMapping(mapping *Mapping) {
|
|
|
// acquire mappings for natds which the mapping was unaware of before.
|
|
|
// Optionally takes renew flag which indicates whether or not we should renew
|
|
|
// mappings with existing natds
|
|
|
-func (s *Service) updateMapping(mapping *Mapping, nats map[string]Device, renew bool) {
|
|
|
+func (s *Service) updateMapping(mapping *Mapping, nats map[string]Device, renew bool, stop chan struct{}) {
|
|
|
var added, removed []Address
|
|
|
|
|
|
renewalTime := time.Duration(s.cfg.Options().NATRenewalM) * time.Minute
|
|
|
mapping.expires = time.Now().Add(renewalTime)
|
|
|
|
|
|
- newAdded, newRemoved := s.verifyExistingMappings(mapping, nats, renew)
|
|
|
+ newAdded, newRemoved := s.verifyExistingMappings(mapping, nats, renew, stop)
|
|
|
added = append(added, newAdded...)
|
|
|
removed = append(removed, newRemoved...)
|
|
|
|
|
|
- newAdded, newRemoved = s.acquireNewMappings(mapping, nats)
|
|
|
+ newAdded, newRemoved = s.acquireNewMappings(mapping, nats, stop)
|
|
|
added = append(added, newAdded...)
|
|
|
removed = append(removed, newRemoved...)
|
|
|
|
|
@@ -197,12 +196,18 @@ func (s *Service) updateMapping(mapping *Mapping, nats map[string]Device, renew
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (s *Service) verifyExistingMappings(mapping *Mapping, nats map[string]Device, renew bool) ([]Address, []Address) {
|
|
|
+func (s *Service) verifyExistingMappings(mapping *Mapping, nats map[string]Device, renew bool, stop chan struct{}) ([]Address, []Address) {
|
|
|
var added, removed []Address
|
|
|
|
|
|
leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
|
|
|
|
|
|
for id, address := range mapping.addressMap() {
|
|
|
+ select {
|
|
|
+ case <-stop:
|
|
|
+ return nil, nil
|
|
|
+ default:
|
|
|
+ }
|
|
|
+
|
|
|
// Delete addresses for NATDevice's that do not exist anymore
|
|
|
nat, ok := nats[id]
|
|
|
if !ok {
|
|
@@ -242,13 +247,19 @@ func (s *Service) verifyExistingMappings(mapping *Mapping, nats map[string]Devic
|
|
|
return added, removed
|
|
|
}
|
|
|
|
|
|
-func (s *Service) acquireNewMappings(mapping *Mapping, nats map[string]Device) ([]Address, []Address) {
|
|
|
+func (s *Service) acquireNewMappings(mapping *Mapping, nats map[string]Device, stop chan struct{}) ([]Address, []Address) {
|
|
|
var added, removed []Address
|
|
|
|
|
|
leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
|
|
|
addrMap := mapping.addressMap()
|
|
|
|
|
|
for id, nat := range nats {
|
|
|
+ select {
|
|
|
+ case <-stop:
|
|
|
+ return nil, nil
|
|
|
+ default:
|
|
|
+ }
|
|
|
+
|
|
|
if _, ok := addrMap[id]; ok {
|
|
|
continue
|
|
|
}
|