//go:build linux || windows || darwin package tun import ( "errors" "sync" "time" "github.com/sagernet/sing/common/atomic" "github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/x/list" ) func (m *networkUpdateMonitor) RegisterCallback(callback NetworkUpdateCallback) *list.Element[NetworkUpdateCallback] { m.access.Lock() defer m.access.Unlock() return m.callbacks.PushBack(callback) } func (m *networkUpdateMonitor) UnregisterCallback(element *list.Element[NetworkUpdateCallback]) { m.access.Lock() defer m.access.Unlock() m.callbacks.Remove(element) } func (m *networkUpdateMonitor) emit() { m.access.Lock() callbacks := m.callbacks.Array() m.access.Unlock() for _, callback := range callbacks { callback() } } type defaultInterfaceMonitor struct { interfaceFinder control.InterfaceFinder overrideAndroidVPN bool underNetworkExtension bool defaultInterface atomic.Pointer[control.Interface] androidVPNEnabled bool noRoute bool networkMonitor NetworkUpdateMonitor checkUpdateTimer *time.Timer element *list.Element[NetworkUpdateCallback] access sync.Mutex callbacks list.List[DefaultInterfaceUpdateCallback] logger logger.Logger } func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, logger logger.Logger, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) { return &defaultInterfaceMonitor{ interfaceFinder: options.InterfaceFinder, overrideAndroidVPN: options.OverrideAndroidVPN, underNetworkExtension: options.UnderNetworkExtension, networkMonitor: networkMonitor, logger: logger, }, nil } func (m *defaultInterfaceMonitor) Start() error { m.postCheckUpdate() m.element = m.networkMonitor.RegisterCallback(m.delayCheckUpdate) return nil } func (m *defaultInterfaceMonitor) delayCheckUpdate() { if m.checkUpdateTimer == nil { m.checkUpdateTimer = time.AfterFunc(time.Second, m.postCheckUpdate) } else { m.checkUpdateTimer.Reset(time.Second) } } func (m *defaultInterfaceMonitor) postCheckUpdate() { err := m.interfaceFinder.Update() if err != nil { m.logger.Error("update interface: ", err) return } err = m.checkUpdate() if errors.Is(err, ErrNoRoute) { if !m.noRoute { m.noRoute = true m.defaultInterface.Store(nil) m.emit(nil, 0) } } else if err != nil { m.logger.Error("check interface: ", err) } else { m.noRoute = false } } func (m *defaultInterfaceMonitor) Close() error { if m.element != nil { m.networkMonitor.UnregisterCallback(m.element) } return nil } func (m *defaultInterfaceMonitor) DefaultInterface() *control.Interface { return m.defaultInterface.Load() } func (m *defaultInterfaceMonitor) OverrideAndroidVPN() bool { return m.overrideAndroidVPN } func (m *defaultInterfaceMonitor) AndroidVPNEnabled() bool { return m.androidVPNEnabled } func (m *defaultInterfaceMonitor) RegisterCallback(callback DefaultInterfaceUpdateCallback) *list.Element[DefaultInterfaceUpdateCallback] { m.access.Lock() defer m.access.Unlock() return m.callbacks.PushBack(callback) } func (m *defaultInterfaceMonitor) UnregisterCallback(element *list.Element[DefaultInterfaceUpdateCallback]) { m.access.Lock() defer m.access.Unlock() m.callbacks.Remove(element) } func (m *defaultInterfaceMonitor) emit(defaultInterface *control.Interface, flags int) { m.access.Lock() callbacks := m.callbacks.Array() m.access.Unlock() for _, callback := range callbacks { callback(defaultInterface, flags) } }