diff --git a/box.go b/box.go index 34ac5470..baebc761 100644 --- a/box.go +++ b/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)) diff --git a/common/sleep/manager.go b/common/sleep/manager.go deleted file mode 100644 index a668e76f..00000000 --- a/common/sleep/manager.go +++ /dev/null @@ -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 -} diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index dc8c5caf..14f0479c 100644 --- a/experimental/libbox/service.go +++ b/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) diff --git a/go.mod b/go.mod index 9ad83653..3c76de0f 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 5645030f..b4b1b389 100644 --- a/go.sum +++ b/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= diff --git a/outbound/urltest.go b/outbound/urltest.go index bd828e4b..79ab0bf8 100644 --- a/outbound/urltest.go +++ b/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 diff --git a/outbound/wireguard.go b/outbound/wireguard.go index eb8f65db..3627e674 100644 --- a/outbound/wireguard.go +++ b/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...)) }, diff --git a/route/router.go b/route/router.go index 568db59a..ceaedb7f 100644 --- a/route/router.go +++ b/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() { diff --git a/test/go.mod b/test/go.mod index db3eec7b..988fca1f 100644 --- a/test/go.mod +++ b/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 diff --git a/test/go.sum b/test/go.sum index cd1dfa24..6eb121e5 100644 --- a/test/go.sum +++ b/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= diff --git a/transport/wireguard/client_bind.go b/transport/wireguard/client_bind.go index 61f5ab7c..2b56f73a 100644 --- a/transport/wireguard/client_bind.go +++ b/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])