Bind network reset dispatch to manager lifecycle

This commit is contained in:
世界
2026-09-20 22:24:38 +08:00
parent 474aa5b5d9
commit 491813c360
+86 -74
View File
@@ -25,6 +25,7 @@ import (
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/winpowrprof"
"github.com/sagernet/sing/common/x/list"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/pause"
@@ -34,37 +35,39 @@ import (
var _ adapter.NetworkManager = (*NetworkManager)(nil)
type NetworkManager struct {
ctx context.Context
logger logger.ContextLogger
router adapter.Router
interfaceFinder *control.DefaultInterfaceFinder
networkInterfaces common.TypedValue[[]adapter.NetworkInterface]
autoDetectInterface bool
defaultOptions adapter.NetworkOptions
autoRedirectOutputMark uint32
networkMonitor tun.NetworkUpdateMonitor
interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager
powerListener winpowrprof.EventListener
pauseManager pause.Manager
platformInterface adapter.PlatformInterface
connectionManager adapter.ConnectionManager
endpoint adapter.EndpointManager
inbound adapter.InboundManager
outbound adapter.OutboundManager
needWIFIState bool
wifiMonitor settings.WIFIMonitor
wifiState adapter.WIFIState
networkEnvironment uint64
stateAccess sync.RWMutex
environmentUpdateAccess sync.Mutex
environmentUpdateTimer *time.Timer
interfaceUpdateAccess sync.Mutex
interfaceUpdateCancel context.CancelFunc
interfaceUpdateRunAccess sync.Mutex
powerUpdateAccess sync.Mutex
powerUpdateCancel context.CancelFunc
started bool
ctx context.Context
logger logger.ContextLogger
router adapter.Router
interfaceFinder *control.DefaultInterfaceFinder
networkInterfaces common.TypedValue[[]adapter.NetworkInterface]
autoDetectInterface bool
defaultOptions adapter.NetworkOptions
autoRedirectOutputMark uint32
networkMonitor tun.NetworkUpdateMonitor
interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager
powerListener winpowrprof.EventListener
pauseManager pause.Manager
platformInterface adapter.PlatformInterface
connectionManager adapter.ConnectionManager
endpoint adapter.EndpointManager
inbound adapter.InboundManager
outbound adapter.OutboundManager
needWIFIState bool
wifiMonitor settings.WIFIMonitor
wifiState adapter.WIFIState
networkEnvironment uint64
stateAccess sync.RWMutex
environmentUpdateAccess sync.Mutex
environmentUpdateTimer *time.Timer
startedCtx context.Context
startedCancel context.CancelFunc
interfaceUpdateElement *list.Element[tun.DefaultInterfaceUpdateCallback]
interfaceUpdateAccess sync.Mutex
interfaceUpdateCancel context.CancelFunc
resetRunAccess sync.Mutex
powerUpdateAccess sync.Mutex
powerUpdateCancel context.CancelFunc
}
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options option.RouteOptions, dnsOptions option.DNSOptions) (*NetworkManager, error) {
@@ -134,13 +137,10 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options
if err != nil {
return nil, E.New("auto_detect_interface unsupported on current platform")
}
interfaceMonitor.RegisterCallback(nm.notifyInterfaceUpdate)
nm.interfaceMonitor = interfaceMonitor
}
} else {
interfaceMonitor := nm.platformInterface.CreateDefaultInterfaceMonitor(logger)
interfaceMonitor.RegisterCallback(nm.notifyInterfaceUpdate)
nm.interfaceMonitor = interfaceMonitor
nm.interfaceMonitor = nm.platformInterface.CreateDefaultInterfaceMonitor(logger)
}
return nm, nil
}
@@ -167,22 +167,6 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
}
}
case adapter.StartStateStart:
if runtime.GOOS == "windows" {
powerListener, err := winpowrprof.NewEventListener(r.notifyWindowsPowerEvent)
if err == nil {
r.powerListener = powerListener
} else {
r.logger.Warn("initialize power listener: ", err)
}
}
if r.powerListener != nil {
monitor.Start("start power listener")
err := r.powerListener.Start()
monitor.Finish()
if err != nil {
return E.Cause(err, "start power listener")
}
}
if C.IsAndroid && r.platformInterface == nil {
monitor.Start("initialize package manager")
packageManager, err := tun.NewPackageManager(tun.PackageManagerOptions{
@@ -217,7 +201,30 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
}
}
}
r.started = true
r.startedCtx, r.startedCancel = context.WithCancel(r.ctx)
if runtime.GOOS == "windows" {
powerListener, err := winpowrprof.NewEventListener(r.notifyWindowsPowerEvent)
if err == nil {
r.powerListener = powerListener
} else {
r.logger.Warn("initialize power listener: ", err)
}
}
if r.powerListener != nil {
monitor.Start("start power listener")
err := r.powerListener.Start()
monitor.Finish()
if err != nil {
return E.Cause(err, "start power listener")
}
}
if r.interfaceMonitor != nil {
r.interfaceUpdateElement = r.interfaceMonitor.RegisterCallback(r.notifyInterfaceUpdate)
// Every monitor implementation has already delivered the initial state when Start returned:
// sing-tun checks routes synchronously, the Apple client blocks on the first NWPathMonitor update,
// and the Android client resolves the active network before setListener returns.
r.notifyInterfaceUpdate(r.interfaceMonitor.DefaultInterface(), 0)
}
}
return nil
}
@@ -235,12 +242,9 @@ func (r *NetworkManager) Initialize(ruleSets []adapter.RuleSet) {
func (r *NetworkManager) Close() error {
monitor := taskmonitor.New(r.logger, C.StopTimeout)
var err error
if r.packageManager != nil {
monitor.Start("close package manager")
err = E.Append(err, r.packageManager.Close(), func(err error) error {
return E.Cause(err, "close package manager")
})
monitor.Finish()
if r.interfaceUpdateElement != nil {
r.interfaceMonitor.UnregisterCallback(r.interfaceUpdateElement)
r.interfaceUpdateElement = nil
}
if r.powerListener != nil {
monitor.Start("close power listener")
@@ -249,6 +253,20 @@ func (r *NetworkManager) Close() error {
})
monitor.Finish()
}
if r.startedCancel != nil {
r.startedCancel()
monitor.Start("wait network reset")
r.resetRunAccess.Lock()
monitor.Finish()
defer r.resetRunAccess.Unlock()
}
if r.packageManager != nil {
monitor.Start("close package manager")
err = E.Append(err, r.packageManager.Close(), func(err error) error {
return E.Cause(err, "close package manager")
})
monitor.Finish()
}
if r.interfaceMonitor != nil {
monitor.Start("close interface monitor")
err = E.Append(err, r.interfaceMonitor.Close(), func(err error) error {
@@ -256,14 +274,6 @@ func (r *NetworkManager) Close() error {
})
monitor.Finish()
}
r.interfaceUpdateAccess.Lock()
interfaceUpdateCancel := r.interfaceUpdateCancel
r.interfaceUpdateCancel = nil
r.interfaceUpdateAccess.Unlock()
if interfaceUpdateCancel != nil {
interfaceUpdateCancel()
}
r.cancelPowerUpdate()
if r.networkMonitor != nil {
monitor.Start("close network monitor")
err = E.Append(err, r.networkMonitor.Close(), func(err error) error {
@@ -516,7 +526,7 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa
return
}
r.pauseManager.NetworkWake()
updateContext, updateCancel := context.WithCancel(r.ctx)
updateContext, updateCancel := context.WithCancel(r.startedCtx)
r.interfaceUpdateAccess.Lock()
previousCancel := r.interfaceUpdateCancel
r.interfaceUpdateCancel = updateCancel
@@ -531,8 +541,8 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa
}
func (r *NetworkManager) updateInterface(ctx context.Context, defaultInterface *control.Interface) {
r.interfaceUpdateRunAccess.Lock()
defer r.interfaceUpdateRunAccess.Unlock()
r.resetRunAccess.Lock()
defer r.resetRunAccess.Unlock()
if ctx.Err() != nil {
return
}
@@ -571,9 +581,6 @@ func (r *NetworkManager) updateInterface(ctx context.Context, defaultInterface *
if ctx.Err() != nil {
return
}
if !r.started {
return
}
r.ResetNetwork(ctx)
}
@@ -582,7 +589,7 @@ func (r *NetworkManager) notifyWindowsPowerEvent(event int) {
case winpowrprof.EVENT_SUSPEND:
r.pauseManager.DevicePause()
r.cancelPowerUpdate()
r.ResetNetwork(r.ctx)
r.ResetNetwork(r.startedCtx)
case winpowrprof.EVENT_RESUME:
if !r.pauseManager.IsDevicePaused() {
return
@@ -590,7 +597,7 @@ func (r *NetworkManager) notifyWindowsPowerEvent(event int) {
fallthrough
case winpowrprof.EVENT_RESUME_AUTOMATIC:
r.pauseManager.DeviceWake()
updateContext, updateCancel := context.WithCancel(r.ctx)
updateContext, updateCancel := context.WithCancel(r.startedCtx)
r.powerUpdateAccess.Lock()
previousCancel := r.powerUpdateCancel
r.powerUpdateCancel = updateCancel
@@ -600,6 +607,11 @@ func (r *NetworkManager) notifyWindowsPowerEvent(event int) {
}
go func() {
defer updateCancel()
r.resetRunAccess.Lock()
defer r.resetRunAccess.Unlock()
if updateContext.Err() != nil {
return
}
r.ResetNetwork(updateContext)
}()
}