Pause recurring tasks when no network

This commit is contained in:
世界 2023-08-07 17:46:51 +08:00
parent ce4c76cdd2
commit 81b847faca
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
11 changed files with 52 additions and 84 deletions

2
box.go
View file

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

View file

@ -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
}

View file

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

2
go.mod
View file

@ -37,7 +37,7 @@ require (
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e 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/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
go.etcd.io/bbolt v1.3.7 go.etcd.io/bbolt v1.3.7

4
go.sum
View file

@ -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/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 h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY= 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-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho=
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 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=

View file

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

View file

@ -166,7 +166,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
if err != nil { if err != nil {
return nil, E.Cause(err, "create WireGuard device") 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{}) { Verbosef: func(format string, args ...interface{}) {
logger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
}, },

View file

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

View file

@ -81,7 +81,7 @@ require (
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // 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/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect

View file

@ -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/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 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-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 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=

View file

@ -5,12 +5,14 @@ import (
"net" "net"
"net/netip" "net/netip"
"sync" "sync"
"time"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service/pause"
"github.com/sagernet/wireguard-go/conn" "github.com/sagernet/wireguard-go/conn"
) )
@ -27,6 +29,7 @@ type ClientBind struct {
isConnect bool isConnect bool
connectAddr M.Socksaddr connectAddr M.Socksaddr
reserved [3]uint8 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 { 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, isConnect: isConnect,
connectAddr: connectAddr, connectAddr: connectAddr,
reserved: reserved, 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")) c.errorHandler.NewError(context.Background(), E.Cause(err, "connect to server"))
err = nil err = nil
time.Sleep(time.Second)
c.pauseManager.WaitActive()
return return
} }
n, addr, err := udpConn.ReadFrom(packets[0]) n, addr, err := udpConn.ReadFrom(packets[0])