sing-tun/monitor_shared.go
2024-11-12 23:18:20 +08:00

134 lines
3.6 KiB
Go

//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)
}
}