diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 8d42d26e..16c04a1f 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -40,7 +40,7 @@ type BoxService struct { clashServer adapter.ClashServer pauseManager pause.Manager - servicePauseFields + iOSPauseFields } func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) { diff --git a/experimental/libbox/service_pause.go b/experimental/libbox/service_pause.go index 0fa9541f..791684ec 100644 --- a/experimental/libbox/service_pause.go +++ b/experimental/libbox/service_pause.go @@ -1,31 +1,33 @@ package libbox import ( - "sync" "time" + + C "github.com/sagernet/sing-box/constant" ) -type servicePauseFields struct { - pauseAccess sync.Mutex - pauseTimer *time.Timer +type iOSPauseFields struct { + endPauseTimer *time.Timer } func (s *BoxService) Pause() { - s.pauseAccess.Lock() - defer s.pauseAccess.Unlock() - if s.pauseTimer != nil { - s.pauseTimer.Stop() + s.pauseManager.DevicePause() + if !C.IsIos { + s.instance.Router().ResetNetwork() + } 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() { - s.pauseAccess.Lock() - defer s.pauseAccess.Unlock() - if s.pauseTimer != nil { - s.pauseTimer.Stop() + if !C.IsIos { + s.pauseManager.DeviceWake() + s.instance.Router().ResetNetwork() } - s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork) } func (s *BoxService) ResetNetwork() { diff --git a/protocol/group/urltest.go b/protocol/group/urltest.go index 564c2373..e52ec906 100644 --- a/protocol/group/urltest.go +++ b/protocol/group/urltest.go @@ -19,6 +19,7 @@ import ( 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/common/x/list" "github.com/sagernet/sing/service" "github.com/sagernet/sing/service/pause" ) @@ -27,10 +28,7 @@ func RegisterURLTest(registry *outbound.Registry) { outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest) } -var ( - _ adapter.OutboundGroup = (*URLTest)(nil) - _ adapter.InterfaceUpdateListener = (*URLTest)(nil) -) +var _ adapter.OutboundGroup = (*URLTest)(nil) type URLTest struct { outbound.Adapter @@ -172,15 +170,12 @@ func (s *URLTest) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose) } -func (s *URLTest) InterfaceUpdated() { - go s.group.CheckOutbounds(true) - return -} - type URLTestGroup struct { ctx context.Context router adapter.Router - outboundManager adapter.OutboundManager + outbound adapter.OutboundManager + pause pause.Manager + pauseCallback *list.Element[pause.Callback] logger log.Logger outbounds []adapter.Outbound link string @@ -189,17 +184,15 @@ type URLTestGroup struct { idleTimeout time.Duration history *urltest.HistoryStorage checking atomic.Bool - pauseManager pause.Manager selectedOutboundTCP adapter.Outbound selectedOutboundUDP adapter.Outbound interruptGroup *interrupt.Group interruptExternalConnections bool - - access sync.Mutex - ticker *time.Ticker - close chan struct{} - started bool - lastActive atomic.TypedValue[time.Time] + access sync.Mutex + ticker *time.Ticker + close chan struct{} + started bool + lastActive atomic.TypedValue[time.Time] } func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManager, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16, idleTimeout time.Duration, interruptExternalConnections bool) (*URLTestGroup, error) { @@ -224,7 +217,7 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage } return &URLTestGroup{ ctx: ctx, - outboundManager: outboundManager, + outbound: outboundManager, logger: logger, outbounds: outbounds, link: link, @@ -233,13 +226,15 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage idleTimeout: idleTimeout, history: history, close: make(chan struct{}), - pauseManager: service.FromContext[pause.Manager](ctx), + pause: service.FromContext[pause.Manager](ctx), interruptGroup: interrupt.NewGroup(), interruptExternalConnections: interruptExternalConnections, }, nil } func (g *URLTestGroup) PostStart() { + g.access.Lock() + defer g.access.Unlock() g.started = true g.lastActive.Store(time.Now()) go g.CheckOutbounds(false) @@ -249,24 +244,25 @@ func (g *URLTestGroup) Touch() { if !g.started { return } + g.access.Lock() + defer g.access.Unlock() if g.ticker != nil { g.lastActive.Store(time.Now()) return } - g.access.Lock() - defer g.access.Unlock() - if g.ticker != nil { - return - } g.ticker = time.NewTicker(g.interval) go g.loopCheck() + g.pauseCallback = pause.RegisterTicker(g.pause, g.ticker, g.interval, nil) } func (g *URLTestGroup) Close() error { + g.access.Lock() + defer g.access.Unlock() if g.ticker == nil { return nil } g.ticker.Stop() + g.pause.UnregisterCallback(g.pauseCallback) close(g.close) return nil } @@ -330,10 +326,11 @@ func (g *URLTestGroup) loopCheck() { g.access.Lock() g.ticker.Stop() g.ticker = nil + g.pause.UnregisterCallback(g.pauseCallback) + g.pauseCallback = nil g.access.Unlock() return } - g.pauseManager.WaitActive() g.CheckOutbounds(false) } } @@ -366,7 +363,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint continue } checked[realTag] = true - p, loaded := g.outboundManager.Outbound(realTag) + p, loaded := g.outbound.Outbound(realTag) if !loaded { continue } diff --git a/protocol/wireguard/endpoint.go b/protocol/wireguard/endpoint.go index 21d72bd9..c9751c36 100644 --- a/protocol/wireguard/endpoint.go +++ b/protocol/wireguard/endpoint.go @@ -120,7 +120,6 @@ func (w *Endpoint) Close() error { func (w *Endpoint) InterfaceUpdated() { w.endpoint.BindUpdate() - return } func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error { diff --git a/protocol/wireguard/outbound.go b/protocol/wireguard/outbound.go index 3e299705..7a516598 100644 --- a/protocol/wireguard/outbound.go +++ b/protocol/wireguard/outbound.go @@ -126,7 +126,6 @@ func (o *Outbound) Close() error { func (o *Outbound) InterfaceUpdated() { o.endpoint.BindUpdate() - return } func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { diff --git a/route/route.go b/route/route.go index dde91db8..d6611b4f 100644 --- a/route/route.go +++ b/route/route.go @@ -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 { - if r.pauseManager.IsDevicePaused() { - return E.New("reject connection to ", metadata.Destination, " while device paused") - } - //nolint:staticcheck if 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 { - if r.pauseManager.IsDevicePaused() { - return E.New("reject packet connection to ", metadata.Destination, " while device paused") - } //nolint:staticcheck if metadata.InboundDetour != "" { if metadata.LastInbound == metadata.InboundDetour { diff --git a/route/rule/rule_set_remote.go b/route/rule/rule_set_remote.go index 9e0c1729..c29d6616 100644 --- a/route/rule/rule_set_remote.go +++ b/route/rule/rule_set_remote.go @@ -103,7 +103,7 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter. } } if s.lastUpdated.IsZero() { - err := s.fetchOnce(ctx, startContext) + err := s.fetch(ctx, startContext) if err != nil { 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() { if time.Since(s.lastUpdated) > s.updateInterval { - err := s.fetchOnce(s.ctx, nil) + err := s.fetch(s.ctx, nil) if err != nil { s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err) } else if s.refs.Load() == 0 { @@ -211,18 +211,21 @@ func (s *RemoteRuleSet) loopUpdate() { case <-s.ctx.Done(): return case <-s.updateTicker.C: - s.pauseManager.WaitActive() - err := s.fetchOnce(s.ctx, nil) - if err != nil { - s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err) - } else if s.refs.Load() == 0 { - s.rules = nil - } + s.updateOnce() } } } -func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTTPStartContext) error { +func (s *RemoteRuleSet) updateOnce() { + err := s.fetch(s.ctx, nil) + if err != nil { + s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err) + } else if s.refs.Load() == 0 { + s.rules = nil + } +} + +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) var httpClient *http.Client if startContext != nil { diff --git a/transport/wireguard/endpoint.go b/transport/wireguard/endpoint.go index 69ce9170..17a58a6c 100644 --- a/transport/wireguard/endpoint.go +++ b/transport/wireguard/endpoint.go @@ -30,7 +30,7 @@ type Endpoint struct { allowedAddress []netip.Prefix tunDevice Device device *device.Device - pauseManager pause.Manager + pause pause.Manager pauseCallback *list.Element[pause.Callback] } @@ -187,9 +187,9 @@ func (e *Endpoint) Start(resolve bool) error { return E.Cause(err, "setup wireguard: \n", ipcConf) } e.device = wgDevice - e.pauseManager = service.FromContext[pause.Manager](e.options.Context) - if e.pauseManager != nil { - e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated) + e.pause = service.FromContext[pause.Manager](e.options.Context) + if e.pause != nil { + e.pauseCallback = e.pause.RegisterCallback(e.onPauseUpdated) } return nil } @@ -217,16 +217,16 @@ func (e *Endpoint) Close() error { e.device.Close() } if e.pauseCallback != nil { - e.pauseManager.UnregisterCallback(e.pauseCallback) + e.pause.UnregisterCallback(e.pauseCallback) } return nil } func (e *Endpoint) onPauseUpdated(event int) { switch event { - case pause.EventDevicePaused: + case pause.EventDevicePaused, pause.EventNetworkPause: e.device.Down() - case pause.EventDeviceWake: + case pause.EventDeviceWake, pause.EventNetworkWake: e.device.Up() } }