mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Improve pause management
This commit is contained in:
parent
24af0766ac
commit
97d41ffde8
@ -40,7 +40,7 @@ type BoxService struct {
|
|||||||
clashServer adapter.ClashServer
|
clashServer adapter.ClashServer
|
||||||
pauseManager pause.Manager
|
pauseManager pause.Manager
|
||||||
|
|
||||||
servicePauseFields
|
iOSPauseFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
|
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
|
||||||
|
@ -1,31 +1,33 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type servicePauseFields struct {
|
type iOSPauseFields struct {
|
||||||
pauseAccess sync.Mutex
|
endPauseTimer *time.Timer
|
||||||
pauseTimer *time.Timer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Pause() {
|
func (s *BoxService) Pause() {
|
||||||
s.pauseAccess.Lock()
|
s.pauseManager.DevicePause()
|
||||||
defer s.pauseAccess.Unlock()
|
if !C.IsIos {
|
||||||
if s.pauseTimer != nil {
|
s.instance.Router().ResetNetwork()
|
||||||
s.pauseTimer.Stop()
|
} else {
|
||||||
|
if s.endPauseTimer == nil {
|
||||||
|
s.endPauseTimer = time.AfterFunc(time.Minute, s.pauseManager.DeviceWake)
|
||||||
|
} else {
|
||||||
|
s.endPauseTimer.Reset(time.Minute)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.pauseTimer = time.AfterFunc(3*time.Second, s.ResetNetwork)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Wake() {
|
func (s *BoxService) Wake() {
|
||||||
s.pauseAccess.Lock()
|
if !C.IsIos {
|
||||||
defer s.pauseAccess.Unlock()
|
s.pauseManager.DeviceWake()
|
||||||
if s.pauseTimer != nil {
|
s.instance.Router().ResetNetwork()
|
||||||
s.pauseTimer.Stop()
|
|
||||||
}
|
}
|
||||||
s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) ResetNetwork() {
|
func (s *BoxService) ResetNetwork() {
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
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/common/x/list"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
"github.com/sagernet/sing/service/pause"
|
"github.com/sagernet/sing/service/pause"
|
||||||
)
|
)
|
||||||
@ -27,10 +28,7 @@ func RegisterURLTest(registry *outbound.Registry) {
|
|||||||
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
|
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var _ adapter.OutboundGroup = (*URLTest)(nil)
|
||||||
_ adapter.OutboundGroup = (*URLTest)(nil)
|
|
||||||
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
outbound.Adapter
|
outbound.Adapter
|
||||||
@ -172,15 +170,12 @@ func (s *URLTest) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
|||||||
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
|
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) InterfaceUpdated() {
|
|
||||||
go s.group.CheckOutbounds(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type URLTestGroup struct {
|
type URLTestGroup struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
outboundManager adapter.OutboundManager
|
outbound adapter.OutboundManager
|
||||||
|
pause pause.Manager
|
||||||
|
pauseCallback *list.Element[pause.Callback]
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
outbounds []adapter.Outbound
|
outbounds []adapter.Outbound
|
||||||
link string
|
link string
|
||||||
@ -189,12 +184,10 @@ type URLTestGroup struct {
|
|||||||
idleTimeout time.Duration
|
idleTimeout time.Duration
|
||||||
history *urltest.HistoryStorage
|
history *urltest.HistoryStorage
|
||||||
checking atomic.Bool
|
checking atomic.Bool
|
||||||
pauseManager pause.Manager
|
|
||||||
selectedOutboundTCP adapter.Outbound
|
selectedOutboundTCP adapter.Outbound
|
||||||
selectedOutboundUDP adapter.Outbound
|
selectedOutboundUDP adapter.Outbound
|
||||||
interruptGroup *interrupt.Group
|
interruptGroup *interrupt.Group
|
||||||
interruptExternalConnections bool
|
interruptExternalConnections bool
|
||||||
|
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
@ -224,7 +217,7 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
|
|||||||
}
|
}
|
||||||
return &URLTestGroup{
|
return &URLTestGroup{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
outboundManager: outboundManager,
|
outbound: outboundManager,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
outbounds: outbounds,
|
outbounds: outbounds,
|
||||||
link: link,
|
link: link,
|
||||||
@ -233,13 +226,15 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
|
|||||||
idleTimeout: idleTimeout,
|
idleTimeout: idleTimeout,
|
||||||
history: history,
|
history: history,
|
||||||
close: make(chan struct{}),
|
close: make(chan struct{}),
|
||||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
pause: service.FromContext[pause.Manager](ctx),
|
||||||
interruptGroup: interrupt.NewGroup(),
|
interruptGroup: interrupt.NewGroup(),
|
||||||
interruptExternalConnections: interruptExternalConnections,
|
interruptExternalConnections: interruptExternalConnections,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) PostStart() {
|
func (g *URLTestGroup) PostStart() {
|
||||||
|
g.access.Lock()
|
||||||
|
defer g.access.Unlock()
|
||||||
g.started = true
|
g.started = true
|
||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
go g.CheckOutbounds(false)
|
go g.CheckOutbounds(false)
|
||||||
@ -249,24 +244,25 @@ func (g *URLTestGroup) Touch() {
|
|||||||
if !g.started {
|
if !g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
g.access.Lock()
|
||||||
|
defer g.access.Unlock()
|
||||||
if g.ticker != nil {
|
if g.ticker != nil {
|
||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.access.Lock()
|
|
||||||
defer g.access.Unlock()
|
|
||||||
if g.ticker != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
g.ticker = time.NewTicker(g.interval)
|
g.ticker = time.NewTicker(g.interval)
|
||||||
go g.loopCheck()
|
go g.loopCheck()
|
||||||
|
g.pauseCallback = pause.RegisterTicker(g.pause, g.ticker, g.interval, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Close() error {
|
func (g *URLTestGroup) Close() error {
|
||||||
|
g.access.Lock()
|
||||||
|
defer g.access.Unlock()
|
||||||
if g.ticker == nil {
|
if g.ticker == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
|
g.pause.UnregisterCallback(g.pauseCallback)
|
||||||
close(g.close)
|
close(g.close)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -330,10 +326,11 @@ func (g *URLTestGroup) loopCheck() {
|
|||||||
g.access.Lock()
|
g.access.Lock()
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
g.ticker = nil
|
g.ticker = nil
|
||||||
|
g.pause.UnregisterCallback(g.pauseCallback)
|
||||||
|
g.pauseCallback = nil
|
||||||
g.access.Unlock()
|
g.access.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.pauseManager.WaitActive()
|
|
||||||
g.CheckOutbounds(false)
|
g.CheckOutbounds(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,7 +363,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
checked[realTag] = true
|
checked[realTag] = true
|
||||||
p, loaded := g.outboundManager.Outbound(realTag)
|
p, loaded := g.outbound.Outbound(realTag)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,6 @@ func (w *Endpoint) Close() error {
|
|||||||
|
|
||||||
func (w *Endpoint) InterfaceUpdated() {
|
func (w *Endpoint) InterfaceUpdated() {
|
||||||
w.endpoint.BindUpdate()
|
w.endpoint.BindUpdate()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
||||||
|
@ -126,7 +126,6 @@ func (o *Outbound) Close() error {
|
|||||||
|
|
||||||
func (o *Outbound) InterfaceUpdated() {
|
func (o *Outbound) InterfaceUpdated() {
|
||||||
o.endpoint.BindUpdate()
|
o.endpoint.BindUpdate()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
@ -60,10 +60,6 @@ func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
||||||
if r.pauseManager.IsDevicePaused() {
|
|
||||||
return E.New("reject connection to ", metadata.Destination, " while device paused")
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if metadata.InboundDetour != "" {
|
if metadata.InboundDetour != "" {
|
||||||
if metadata.LastInbound == metadata.InboundDetour {
|
if metadata.LastInbound == metadata.InboundDetour {
|
||||||
@ -186,9 +182,6 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
||||||
if r.pauseManager.IsDevicePaused() {
|
|
||||||
return E.New("reject packet connection to ", metadata.Destination, " while device paused")
|
|
||||||
}
|
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if metadata.InboundDetour != "" {
|
if metadata.InboundDetour != "" {
|
||||||
if metadata.LastInbound == metadata.InboundDetour {
|
if metadata.LastInbound == metadata.InboundDetour {
|
||||||
|
@ -103,7 +103,7 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.lastUpdated.IsZero() {
|
if s.lastUpdated.IsZero() {
|
||||||
err := s.fetchOnce(ctx, startContext)
|
err := s.fetch(ctx, startContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "initial rule-set: ", s.options.Tag)
|
return E.Cause(err, "initial rule-set: ", s.options.Tag)
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ func (s *RemoteRuleSet) loadBytes(content []byte) error {
|
|||||||
|
|
||||||
func (s *RemoteRuleSet) loopUpdate() {
|
func (s *RemoteRuleSet) loopUpdate() {
|
||||||
if time.Since(s.lastUpdated) > s.updateInterval {
|
if time.Since(s.lastUpdated) > s.updateInterval {
|
||||||
err := s.fetchOnce(s.ctx, nil)
|
err := s.fetch(s.ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
||||||
} else if s.refs.Load() == 0 {
|
} else if s.refs.Load() == 0 {
|
||||||
@ -211,18 +211,21 @@ func (s *RemoteRuleSet) loopUpdate() {
|
|||||||
case <-s.ctx.Done():
|
case <-s.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-s.updateTicker.C:
|
case <-s.updateTicker.C:
|
||||||
s.pauseManager.WaitActive()
|
s.updateOnce()
|
||||||
err := s.fetchOnce(s.ctx, nil)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RemoteRuleSet) updateOnce() {
|
||||||
|
err := s.fetch(s.ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
||||||
} else if s.refs.Load() == 0 {
|
} else if s.refs.Load() == 0 {
|
||||||
s.rules = nil
|
s.rules = nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTTPStartContext) error {
|
func (s *RemoteRuleSet) fetch(ctx context.Context, startContext *adapter.HTTPStartContext) error {
|
||||||
s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL)
|
s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL)
|
||||||
var httpClient *http.Client
|
var httpClient *http.Client
|
||||||
if startContext != nil {
|
if startContext != nil {
|
||||||
|
@ -30,7 +30,7 @@ type Endpoint struct {
|
|||||||
allowedAddress []netip.Prefix
|
allowedAddress []netip.Prefix
|
||||||
tunDevice Device
|
tunDevice Device
|
||||||
device *device.Device
|
device *device.Device
|
||||||
pauseManager pause.Manager
|
pause pause.Manager
|
||||||
pauseCallback *list.Element[pause.Callback]
|
pauseCallback *list.Element[pause.Callback]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +187,9 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
return E.Cause(err, "setup wireguard: \n", ipcConf)
|
return E.Cause(err, "setup wireguard: \n", ipcConf)
|
||||||
}
|
}
|
||||||
e.device = wgDevice
|
e.device = wgDevice
|
||||||
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
|
e.pause = service.FromContext[pause.Manager](e.options.Context)
|
||||||
if e.pauseManager != nil {
|
if e.pause != nil {
|
||||||
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
|
e.pauseCallback = e.pause.RegisterCallback(e.onPauseUpdated)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -217,16 +217,16 @@ func (e *Endpoint) Close() error {
|
|||||||
e.device.Close()
|
e.device.Close()
|
||||||
}
|
}
|
||||||
if e.pauseCallback != nil {
|
if e.pauseCallback != nil {
|
||||||
e.pauseManager.UnregisterCallback(e.pauseCallback)
|
e.pause.UnregisterCallback(e.pauseCallback)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Endpoint) onPauseUpdated(event int) {
|
func (e *Endpoint) onPauseUpdated(event int) {
|
||||||
switch event {
|
switch event {
|
||||||
case pause.EventDevicePaused:
|
case pause.EventDevicePaused, pause.EventNetworkPause:
|
||||||
e.device.Down()
|
e.device.Down()
|
||||||
case pause.EventDeviceWake:
|
case pause.EventDeviceWake, pause.EventNetworkWake:
|
||||||
e.device.Up()
|
e.device.Up()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user