Browse Source

Pause recurring tasks when no network

世界 2 years ago
parent
commit
81b847faca
11 changed files with 52 additions and 84 deletions
  1. 2 0
      box.go
  2. 0 43
      common/sleep/manager.go
  3. 7 7
      experimental/libbox/service.go
  4. 1 1
      go.mod
  5. 2 2
      go.sum
  6. 4 6
      outbound/urltest.go
  7. 1 1
      outbound/wireguard.go
  8. 27 23
      route/router.go
  9. 1 1
      test/go.mod
  10. 1 0
      test/go.sum
  11. 6 0
      transport/wireguard/client_bind.go

+ 2 - 0
box.go

@@ -19,6 +19,7 @@ import (
 	"github.com/sagernet/sing/common"
 	E "github.com/sagernet/sing/common/exceptions"
 	F "github.com/sagernet/sing/common/format"
+	"github.com/sagernet/sing/service/pause"
 )
 
 var _ adapter.Service = (*Box)(nil)
@@ -46,6 +47,7 @@ func New(options Options) (*Box, error) {
 	if ctx == nil {
 		ctx = context.Background()
 	}
+	ctx = pause.ContextWithDefaultManager(ctx)
 	createdAt := time.Now()
 	experimentalOptions := common.PtrValueOrDefault(options.Experimental)
 	applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))

+ 0 - 43
common/sleep/manager.go

@@ -1,43 +0,0 @@
-package sleep
-
-import (
-	"sync"
-)
-
-type Manager struct {
-	access sync.Mutex
-	done   chan struct{}
-}
-
-func NewManager() *Manager {
-	closedChan := make(chan struct{})
-	close(closedChan)
-	return &Manager{
-		done: closedChan,
-	}
-}
-
-func (m *Manager) Sleep() {
-	m.access.Lock()
-	defer m.access.Unlock()
-	select {
-	case <-m.done:
-	default:
-		return
-	}
-	m.done = make(chan struct{})
-}
-
-func (m *Manager) Wake() {
-	m.access.Lock()
-	defer m.access.Unlock()
-	select {
-	case <-m.done:
-	default:
-		close(m.done)
-	}
-}
-
-func (m *Manager) Active() <-chan struct{} {
-	return m.done
-}

+ 7 - 7
experimental/libbox/service.go

@@ -8,7 +8,6 @@ import (
 	"github.com/sagernet/sing-box"
 	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/common/process"
-	"github.com/sagernet/sing-box/common/sleep"
 	"github.com/sagernet/sing-box/common/urltest"
 	"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
 	"github.com/sagernet/sing-box/experimental/libbox/platform"
@@ -21,13 +20,14 @@ import (
 	N "github.com/sagernet/sing/common/network"
 	"github.com/sagernet/sing/service"
 	"github.com/sagernet/sing/service/filemanager"
+	"github.com/sagernet/sing/service/pause"
 )
 
 type BoxService struct {
 	ctx          context.Context
 	cancel       context.CancelFunc
 	instance     *box.Box
-	sleepManager *sleep.Manager
+	pauseManager pause.Manager
 }
 
 func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
@@ -38,8 +38,8 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
 	ctx, cancel := context.WithCancel(context.Background())
 	ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
 	ctx = service.ContextWithPtr(ctx, urltest.NewHistoryStorage())
-	sleepManager := sleep.NewManager()
-	ctx = service.ContextWithPtr(ctx, sleepManager)
+	sleepManager := pause.NewDefaultManager(ctx)
+	ctx = pause.ContextWithManager(ctx, sleepManager)
 	instance, err := box.New(box.Options{
 		Context:           ctx,
 		Options:           options,
@@ -53,7 +53,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
 		ctx:          ctx,
 		cancel:       cancel,
 		instance:     instance,
-		sleepManager: sleepManager,
+		pauseManager: sleepManager,
 	}, nil
 }
 
@@ -67,12 +67,12 @@ func (s *BoxService) Close() error {
 }
 
 func (s *BoxService) Sleep() {
-	s.sleepManager.Sleep()
+	s.pauseManager.DevicePause()
 	_ = s.instance.Router().ResetNetwork()
 }
 
 func (s *BoxService) Wake() {
-	s.sleepManager.Wake()
+	s.pauseManager.DeviceWake()
 }
 
 var _ platform.Interface = (*platformInterfaceWrapper)(nil)

+ 1 - 1
go.mod

@@ -37,7 +37,7 @@ require (
 	github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
 	github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
 	github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
-	github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77
+	github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f
 	github.com/spf13/cobra v1.7.0
 	github.com/stretchr/testify v1.8.4
 	go.etcd.io/bbolt v1.3.7

+ 2 - 2
go.sum

@@ -137,8 +137,8 @@ github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfI
 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
 github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
 github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
-github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
-github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
+github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho=
+github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk=
 github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
 github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
 github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=

+ 4 - 6
outbound/urltest.go

@@ -8,7 +8,6 @@ import (
 	"time"
 
 	"github.com/sagernet/sing-box/adapter"
-	"github.com/sagernet/sing-box/common/sleep"
 	"github.com/sagernet/sing-box/common/urltest"
 	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/log"
@@ -20,6 +19,7 @@ import (
 	M "github.com/sagernet/sing/common/metadata"
 	N "github.com/sagernet/sing/common/network"
 	"github.com/sagernet/sing/service"
+	"github.com/sagernet/sing/service/pause"
 )
 
 var (
@@ -153,7 +153,7 @@ type URLTestGroup struct {
 	tolerance    uint16
 	history      *urltest.HistoryStorage
 	checking     atomic.Bool
-	sleepManager *sleep.Manager
+	pauseManager pause.Manager
 
 	access sync.Mutex
 	ticker *time.Ticker
@@ -184,7 +184,7 @@ func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logg
 		tolerance:    tolerance,
 		history:      history,
 		close:        make(chan struct{}),
-		sleepManager: service.PtrFromContext[sleep.Manager](ctx),
+		pauseManager: pause.ManagerFromContext(ctx),
 	}
 }
 
@@ -266,9 +266,7 @@ func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
 func (g *URLTestGroup) loopCheck() {
 	go g.CheckOutbounds(true)
 	for {
-		if g.sleepManager != nil {
-			<-g.sleepManager.Active()
-		}
+		g.pauseManager.WaitActive()
 		select {
 		case <-g.close:
 			return

+ 1 - 1
outbound/wireguard.go

@@ -166,7 +166,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
 	if err != nil {
 		return nil, E.Cause(err, "create WireGuard device")
 	}
-	wgDevice := device.NewDevice(wireTunDevice, outbound.bind, &device.Logger{
+	wgDevice := device.NewDevice(ctx, wireTunDevice, outbound.bind, &device.Logger{
 		Verbosef: func(format string, args ...interface{}) {
 			logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
 		},

+ 27 - 23
route/router.go

@@ -2,6 +2,7 @@ package route
 
 import (
 	"context"
+	"errors"
 	"net"
 	"net/netip"
 	"net/url"
@@ -38,6 +39,7 @@ import (
 	M "github.com/sagernet/sing/common/metadata"
 	N "github.com/sagernet/sing/common/network"
 	"github.com/sagernet/sing/common/uot"
+	"github.com/sagernet/sing/service/pause"
 )
 
 var _ adapter.Router = (*Router)(nil)
@@ -78,6 +80,7 @@ type Router struct {
 	packageManager                     tun.PackageManager
 	processSearcher                    process.Searcher
 	timeService                        adapter.TimeService
+	pauseManager                       pause.Manager
 	clashServer                        adapter.ClashServer
 	v2rayServer                        adapter.V2RayServer
 	platformInterface                  platform.Interface
@@ -109,6 +112,7 @@ func NewRouter(
 		autoDetectInterface:   options.AutoDetectInterface,
 		defaultInterface:      options.DefaultInterface,
 		defaultMark:           options.DefaultMark,
+		pauseManager:          pause.ManagerFromContext(ctx),
 		platformInterface:     platformInterface,
 	}
 	router.dnsClient = dns.NewClient(dns.ClientOptions{
@@ -260,32 +264,30 @@ func NewRouter(
 		return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || inbound.TunOptions.AutoRoute
 	})
 
-	if needInterfaceMonitor {
-		if !usePlatformDefaultInterfaceMonitor {
-			networkMonitor, err := tun.NewNetworkUpdateMonitor(router.logger)
-			if err != os.ErrInvalid {
-				if err != nil {
-					return nil, err
-				}
-				router.networkMonitor = networkMonitor
-				networkMonitor.RegisterCallback(func() {
-					_ = router.interfaceFinder.update()
-				})
-				interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, router.logger, tun.DefaultInterfaceMonitorOptions{
-					OverrideAndroidVPN:    options.OverrideAndroidVPN,
-					UnderNetworkExtension: platformInterface != nil && platformInterface.UnderNetworkExtension(),
-				})
-				if err != nil {
-					return nil, E.New("auto_detect_interface unsupported on current platform")
-				}
-				interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
-				router.interfaceMonitor = interfaceMonitor
+	if !usePlatformDefaultInterfaceMonitor {
+		networkMonitor, err := tun.NewNetworkUpdateMonitor(router.logger)
+		if !((err != nil && !needInterfaceMonitor) || errors.Is(err, os.ErrInvalid)) {
+			if err != nil {
+				return nil, err
+			}
+			router.networkMonitor = networkMonitor
+			networkMonitor.RegisterCallback(func() {
+				_ = router.interfaceFinder.update()
+			})
+			interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, router.logger, tun.DefaultInterfaceMonitorOptions{
+				OverrideAndroidVPN:    options.OverrideAndroidVPN,
+				UnderNetworkExtension: platformInterface != nil && platformInterface.UnderNetworkExtension(),
+			})
+			if err != nil {
+				return nil, E.New("auto_detect_interface unsupported on current platform")
 			}
-		} else {
-			interfaceMonitor := platformInterface.CreateDefaultInterfaceMonitor(router.logger)
 			interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
 			router.interfaceMonitor = interfaceMonitor
 		}
+	} else {
+		interfaceMonitor := platformInterface.CreateDefaultInterfaceMonitor(router.logger)
+		interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
+		router.interfaceMonitor = interfaceMonitor
 	}
 
 	needFindProcess := hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess
@@ -974,8 +976,10 @@ func (r *Router) NewError(ctx context.Context, err error) {
 
 func (r *Router) notifyNetworkUpdate(event int) {
 	if event == tun.EventNoRoute {
-		r.logger.Info("missing default interface")
+		r.pauseManager.NetworkPause()
+		r.logger.Error("missing default interface")
 	} else {
+		r.pauseManager.NetworkWake()
 		if C.IsAndroid && r.platformInterface == nil {
 			var vpnStatus string
 			if r.interfaceMonitor.AndroidVPNEnabled() {

+ 1 - 1
test/go.mod

@@ -81,7 +81,7 @@ require (
 	github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
 	github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
 	github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
-	github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect
+	github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect
 	github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect

+ 1 - 0
test/go.sum

@@ -161,6 +161,7 @@ github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+V
 github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
+github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk=
 github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
 github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=

+ 6 - 0
transport/wireguard/client_bind.go

@@ -5,12 +5,14 @@ import (
 	"net"
 	"net/netip"
 	"sync"
+	"time"
 
 	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common/bufio"
 	E "github.com/sagernet/sing/common/exceptions"
 	M "github.com/sagernet/sing/common/metadata"
 	N "github.com/sagernet/sing/common/network"
+	"github.com/sagernet/sing/service/pause"
 	"github.com/sagernet/wireguard-go/conn"
 )
 
@@ -27,6 +29,7 @@ type ClientBind struct {
 	isConnect           bool
 	connectAddr         M.Socksaddr
 	reserved            [3]uint8
+	pauseManager        pause.Manager
 }
 
 func NewClientBind(ctx context.Context, errorHandler E.Handler, dialer N.Dialer, isConnect bool, connectAddr M.Socksaddr, reserved [3]uint8) *ClientBind {
@@ -38,6 +41,7 @@ func NewClientBind(ctx context.Context, errorHandler E.Handler, dialer N.Dialer,
 		isConnect:           isConnect,
 		connectAddr:         connectAddr,
 		reserved:            reserved,
+		pauseManager:        pause.ManagerFromContext(ctx),
 	}
 }
 
@@ -111,6 +115,8 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
 		}
 		c.errorHandler.NewError(context.Background(), E.Cause(err, "connect to server"))
 		err = nil
+		time.Sleep(time.Second)
+		c.pauseManager.WaitActive()
 		return
 	}
 	n, addr, err := udpConn.ReadFrom(packets[0])