mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
Handle network update callbacks in background
This commit is contained in:
+4
-3
@@ -1,6 +1,7 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -32,8 +33,8 @@ type NetworkManager interface {
|
||||
PackageManager() tun.PackageManager
|
||||
NeedWIFIState() bool
|
||||
WIFIState() WIFIState
|
||||
UpdateWIFIState()
|
||||
ResetNetwork()
|
||||
UpdateWIFIState(ctx context.Context)
|
||||
ResetNetwork(ctx context.Context)
|
||||
}
|
||||
|
||||
type NetworkOptions struct {
|
||||
@@ -48,7 +49,7 @@ type NetworkOptions struct {
|
||||
}
|
||||
|
||||
type InterfaceUpdateListener interface {
|
||||
InterfaceUpdated()
|
||||
InterfaceUpdated(ctx context.Context)
|
||||
}
|
||||
|
||||
type WIFIState struct {
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/sing-box/option"
|
||||
@@ -29,7 +30,7 @@ type PlatformInterface interface {
|
||||
|
||||
ClearDNSCache()
|
||||
RequestPermissionForWIFIState() error
|
||||
ReadWIFIState() WIFIState
|
||||
ReadWIFIState(ctx context.Context) WIFIState
|
||||
|
||||
UsePlatformConnectionOwnerFinder() bool
|
||||
FindConnectionOwner(request *FindConnectionOwnerRequest) (*ConnectionOwner, error)
|
||||
|
||||
@@ -113,7 +113,7 @@ func (l *Listener) Start() error {
|
||||
}
|
||||
err = systemProxy.Enable()
|
||||
if err != nil {
|
||||
return E.Cause(err, "set system proxy")
|
||||
return E.Errors(E.Cause(err, "set system proxy"), systemProxy.Close())
|
||||
}
|
||||
l.systemProxy = systemProxy
|
||||
}
|
||||
@@ -123,8 +123,11 @@ func (l *Listener) Start() error {
|
||||
func (l *Listener) Close() error {
|
||||
l.shutdown.Store(true)
|
||||
var err error
|
||||
if l.systemProxy != nil && l.systemProxy.IsEnabled() {
|
||||
err = l.systemProxy.Disable()
|
||||
if l.systemProxy != nil {
|
||||
if l.systemProxy.IsEnabled() {
|
||||
err = l.systemProxy.Disable()
|
||||
}
|
||||
err = E.Errors(err, l.systemProxy.Close())
|
||||
}
|
||||
return E.Errors(err, common.Close(
|
||||
l.tcpListener,
|
||||
|
||||
@@ -55,6 +55,10 @@ func (p *AndroidSystemProxy) Enable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *AndroidSystemProxy) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *AndroidSystemProxy) Disable() error {
|
||||
err := p.runAndroidShell("settings", "put", "global", "http_proxy", ":0")
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-tun"
|
||||
@@ -16,11 +17,14 @@ import (
|
||||
)
|
||||
|
||||
type DarwinSystemProxy struct {
|
||||
ctx context.Context
|
||||
monitor tun.DefaultInterfaceMonitor
|
||||
interfaceName string
|
||||
element *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
serverAddr M.Socksaddr
|
||||
supportSOCKS bool
|
||||
access sync.Mutex
|
||||
updateCancel context.CancelFunc
|
||||
isEnabled bool
|
||||
}
|
||||
|
||||
@@ -30,6 +34,7 @@ func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bo
|
||||
return nil, E.New("missing interface monitor")
|
||||
}
|
||||
proxy := &DarwinSystemProxy{
|
||||
ctx: ctx,
|
||||
monitor: interfaceMonitor,
|
||||
serverAddr: serverAddr,
|
||||
supportSOCKS: supportSOCKS,
|
||||
@@ -39,14 +44,36 @@ func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bo
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) IsEnabled() bool {
|
||||
p.access.Lock()
|
||||
defer p.access.Unlock()
|
||||
return p.isEnabled
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) Enable() error {
|
||||
return p.update0()
|
||||
p.access.Lock()
|
||||
defer p.access.Unlock()
|
||||
return p.updateLocked(p.ctx)
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) Disable() error {
|
||||
p.access.Lock()
|
||||
defer p.access.Unlock()
|
||||
return p.disableLocked()
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) Close() error {
|
||||
p.access.Lock()
|
||||
updateCancel := p.updateCancel
|
||||
p.updateCancel = nil
|
||||
p.access.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
p.monitor.UnregisterCallback(p.element)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) disableLocked() error {
|
||||
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -67,19 +94,35 @@ func (p *DarwinSystemProxy) Disable() error {
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) routeUpdate(defaultInterface *control.Interface, flags int) {
|
||||
if !p.isEnabled || defaultInterface == nil {
|
||||
if defaultInterface == nil {
|
||||
return
|
||||
}
|
||||
_ = p.update0()
|
||||
updateContext, updateCancel := context.WithCancel(p.ctx)
|
||||
p.access.Lock()
|
||||
previousCancel := p.updateCancel
|
||||
p.updateCancel = updateCancel
|
||||
p.access.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
go func() {
|
||||
defer updateCancel()
|
||||
p.access.Lock()
|
||||
defer p.access.Unlock()
|
||||
if !p.isEnabled || updateContext.Err() != nil {
|
||||
return
|
||||
}
|
||||
_ = p.updateLocked(updateContext)
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *DarwinSystemProxy) update0() error {
|
||||
func (p *DarwinSystemProxy) updateLocked(ctx context.Context) error {
|
||||
newInterface := p.monitor.DefaultInterface()
|
||||
if p.interfaceName == newInterface.Name {
|
||||
if newInterface == nil || p.interfaceName == newInterface.Name {
|
||||
return nil
|
||||
}
|
||||
if p.interfaceName != "" {
|
||||
_ = p.Disable()
|
||||
_ = p.disableLocked()
|
||||
}
|
||||
p.interfaceName = newInterface.Name
|
||||
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
|
||||
@@ -87,15 +130,27 @@ func (p *DarwinSystemProxy) update0() error {
|
||||
return err
|
||||
}
|
||||
if p.supportSOCKS {
|
||||
err = ctx.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ctx.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ctx.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -118,6 +118,10 @@ func (p *LinuxSystemProxy) Enable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LinuxSystemProxy) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LinuxSystemProxy) Disable() error {
|
||||
if p.hasGSettings {
|
||||
err := p.execute("gsettings", "set", "org.gnome.system.proxy", "mode", "none")
|
||||
|
||||
@@ -36,6 +36,10 @@ func (p *WindowsSystemProxy) Enable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *WindowsSystemProxy) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *WindowsSystemProxy) Disable() error {
|
||||
err := wininet.ClearSystemProxy()
|
||||
if err != nil {
|
||||
|
||||
@@ -4,4 +4,5 @@ type SystemProxy interface {
|
||||
IsEnabled() bool
|
||||
Enable() error
|
||||
Disable() error
|
||||
Close() error
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package settings
|
||||
|
||||
import "github.com/sagernet/sing-box/adapter"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
)
|
||||
|
||||
type WIFIMonitor interface {
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
ReadWIFIState(ctx context.Context) adapter.WIFIState
|
||||
Start() error
|
||||
Close() error
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
@@ -27,8 +29,8 @@ func NewWIFIMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
|
||||
return nil, E.Cause(E.Errors(errors...), "no supported WIFI manager found")
|
||||
}
|
||||
|
||||
func (m *LinuxWIFIMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
return m.monitor.ReadWIFIState()
|
||||
func (m *LinuxWIFIMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
return m.monitor.ReadWIFIState(ctx)
|
||||
}
|
||||
|
||||
func (m *LinuxWIFIMonitor) Start() error {
|
||||
|
||||
@@ -35,8 +35,8 @@ func newConnManMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
|
||||
return &connmanMonitor{conn: conn, callback: callback}, nil
|
||||
}
|
||||
|
||||
func (m *connmanMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
func (m *connmanMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmObj := m.conn.Object("net.connman", "/")
|
||||
@@ -120,7 +120,7 @@ func (m *connmanMonitor) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
go m.monitorSignals(ctx, m.signalChan, state)
|
||||
m.callback(state)
|
||||
|
||||
@@ -139,7 +139,7 @@ func (m *connmanMonitor) monitorSignals(ctx context.Context, signalChan chan *db
|
||||
// godbus Signal.Name uses "interface.member" format (e.g. "net.connman.Service.PropertyChanged"),
|
||||
// not just the member name. This differs from the D-Bus signal member in the match rule.
|
||||
if signal.Name == "net.connman.Service.PropertyChanged" {
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
if state != lastState {
|
||||
lastState = state
|
||||
m.callback(state)
|
||||
|
||||
@@ -35,8 +35,8 @@ func newIWDMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
|
||||
return &iwdMonitor{conn: conn, callback: callback}, nil
|
||||
}
|
||||
|
||||
func (m *iwdMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
func (m *iwdMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
iwdObj := m.conn.Object("net.connman.iwd", "/")
|
||||
@@ -144,7 +144,7 @@ func (m *iwdMonitor) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
go m.monitorSignals(ctx, m.signalChan, state)
|
||||
m.callback(state)
|
||||
|
||||
@@ -161,7 +161,7 @@ func (m *iwdMonitor) monitorSignals(ctx context.Context, signalChan chan *dbus.S
|
||||
return
|
||||
}
|
||||
if signal.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
if state != lastState {
|
||||
lastState = state
|
||||
m.callback(state)
|
||||
|
||||
@@ -36,8 +36,8 @@ func newNetworkManagerMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, er
|
||||
return &networkManagerMonitor{conn: conn, callback: callback}, nil
|
||||
}
|
||||
|
||||
func (m *networkManagerMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
func (m *networkManagerMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
nmObj := m.conn.Object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager")
|
||||
@@ -119,7 +119,7 @@ func (m *networkManagerMonitor) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
go m.monitorSignals(ctx, m.signalChan, state)
|
||||
m.callback(state)
|
||||
|
||||
@@ -136,7 +136,7 @@ func (m *networkManagerMonitor) monitorSignals(ctx context.Context, signalChan c
|
||||
return
|
||||
}
|
||||
if signal.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
if state != lastState {
|
||||
lastState = state
|
||||
m.callback(state)
|
||||
|
||||
@@ -52,7 +52,7 @@ func newWpaSupplicantMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, err
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
func (m *wpaSupplicantMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
func (m *wpaSupplicantMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
id := wpaSocketCounter.Add(1)
|
||||
localAddr := &net.UnixAddr{Name: fmt.Sprintf("@sing-box-wpa-%d-%d", os.Getpid(), id), Net: "unixgram"}
|
||||
remoteAddr := &net.UnixAddr{Name: m.socketPath, Net: "unixgram"}
|
||||
@@ -63,6 +63,15 @@ func (m *wpaSupplicantMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
conn.SetDeadline(time.Now())
|
||||
case <-done:
|
||||
}
|
||||
}()
|
||||
|
||||
status, err := m.sendCommand(conn, "STATUS")
|
||||
if err != nil {
|
||||
@@ -124,7 +133,7 @@ func (m *wpaSupplicantMonitor) Start() error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m.cancel = cancel
|
||||
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
go m.monitorEvents(ctx, state)
|
||||
m.callback(state)
|
||||
|
||||
@@ -202,7 +211,7 @@ func (m *wpaSupplicantMonitor) monitorEvents(ctx context.Context, lastState adap
|
||||
debounceTimer.Stop()
|
||||
}
|
||||
debounceTimer = time.AfterFunc(500*time.Millisecond, func() {
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(ctx)
|
||||
if state != lastState {
|
||||
lastState = state
|
||||
m.callback(state)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@@ -15,7 +16,7 @@ func NewWIFIMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (m *stubWIFIMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
func (m *stubWIFIMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ func NewWIFIMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *windowsWIFIMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
func (m *windowsWIFIMonitor) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
interfaces, err := winwlanapi.EnumInterfaces(m.handle)
|
||||
if err != nil || len(interfaces) == 0 {
|
||||
return adapter.WIFIState{}
|
||||
@@ -92,7 +92,7 @@ func (m *windowsWIFIMonitor) Start() error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m.cancel = cancel
|
||||
|
||||
m.lastState = m.ReadWIFIState()
|
||||
m.lastState = m.ReadWIFIState(ctx)
|
||||
|
||||
callbackFunc := func(data *winwlanapi.NotificationData, callbackContext uintptr) uintptr {
|
||||
if data.NotificationSource != winwlanapi.NotificationSourceACM {
|
||||
@@ -126,7 +126,7 @@ func (m *windowsWIFIMonitor) checkAndNotify() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
state := m.ReadWIFIState()
|
||||
state := m.ReadWIFIState(context.Background())
|
||||
if state != m.lastState {
|
||||
m.lastState = state
|
||||
if m.callback != nil {
|
||||
|
||||
+39
-11
@@ -55,6 +55,8 @@ type Transport struct {
|
||||
platformInterface adapter.PlatformInterface
|
||||
interfaceName string
|
||||
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
updateAccess sync.Mutex
|
||||
updateCancel context.CancelFunc
|
||||
refreshAccess sync.Mutex
|
||||
savedState atomic.Pointer[transportState]
|
||||
ndots int
|
||||
@@ -126,6 +128,13 @@ func (t *Transport) Close() error {
|
||||
if t.interfaceCallback != nil {
|
||||
t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
t.updateAccess.Lock()
|
||||
updateCancel := t.updateCancel
|
||||
t.updateCancel = nil
|
||||
t.updateAccess.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
t.refreshAccess.Lock()
|
||||
defer t.refreshAccess.Unlock()
|
||||
state := t.savedState.Swap(nil)
|
||||
@@ -243,7 +252,7 @@ func (t *Transport) fetch() error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return t.updateServersLocked()
|
||||
return t.updateServersLocked(t.ctx)
|
||||
}
|
||||
|
||||
func (t *Transport) startRefresh() {
|
||||
@@ -256,7 +265,7 @@ func (t *Transport) startRefresh() {
|
||||
if state != nil && time.Since(state.updatedAt) < C.DHCPTTL {
|
||||
return
|
||||
}
|
||||
err := t.updateServersLocked()
|
||||
err := t.updateServersLocked(t.ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, errInterfaceIsCellular) && t.optional {
|
||||
t.logger.Debug(E.Cause(err, "dhcp: refresh DNS servers"))
|
||||
@@ -293,17 +302,20 @@ func (t *Transport) fetchInterface() (*control.Interface, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) updateServersLocked() error {
|
||||
func (t *Transport) updateServersLocked(ctx context.Context) error {
|
||||
iface, err := t.fetchInterface()
|
||||
if err != nil {
|
||||
t.storeFailureLocked(err)
|
||||
return E.Cause(err, "prepare interface")
|
||||
}
|
||||
t.logger.Info("dhcp: query DNS servers on ", iface.Name)
|
||||
fetchCtx, cancel := context.WithTimeout(t.ctx, C.DHCPTimeout)
|
||||
fetchCtx, cancel := context.WithTimeout(ctx, C.DHCPTimeout)
|
||||
err = t.fetchServers0(fetchCtx, iface)
|
||||
cancel()
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return err
|
||||
}
|
||||
t.storeFailureLocked(err)
|
||||
return err
|
||||
}
|
||||
@@ -331,16 +343,28 @@ func (t *Transport) storeFailureLocked(err error) {
|
||||
}
|
||||
|
||||
func (t *Transport) interfaceUpdated(defaultInterface *control.Interface, flags int) {
|
||||
t.refreshAccess.Lock()
|
||||
err := t.updateServersLocked()
|
||||
t.refreshAccess.Unlock()
|
||||
if err != nil {
|
||||
updateContext, updateCancel := context.WithCancel(t.ctx)
|
||||
t.updateAccess.Lock()
|
||||
previousCancel := t.updateCancel
|
||||
t.updateCancel = updateCancel
|
||||
t.updateAccess.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
go func() {
|
||||
defer updateCancel()
|
||||
t.refreshAccess.Lock()
|
||||
err := t.updateServersLocked(updateContext)
|
||||
t.refreshAccess.Unlock()
|
||||
if err == nil || updateContext.Err() != nil {
|
||||
return
|
||||
}
|
||||
if errors.Is(err, errInterfaceIsCellular) && t.optional {
|
||||
t.logger.Debug(E.Cause(errInterfaceIsCellular, "dhcp: update DNS servers"))
|
||||
} else {
|
||||
t.logger.Error("dhcp: update DNS servers: ", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface) error {
|
||||
@@ -356,11 +380,15 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface)
|
||||
err error
|
||||
)
|
||||
for range 5 {
|
||||
packetConn, err = listener.ListenPacket(t.ctx, "udp4", listenAddr)
|
||||
packetConn, err = listener.ListenPacket(ctx, "udp4", listenAddr)
|
||||
if err == nil || !errors.Is(err, syscall.EADDRINUSE) {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -58,6 +58,10 @@ type DBusResolvedResolver struct {
|
||||
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
systemBus *dbus.Conn
|
||||
savedServerSet atomic.Pointer[resolvedServerSet]
|
||||
updateAccess sync.Mutex
|
||||
updateCancel context.CancelFunc
|
||||
updateRunAccess sync.Mutex
|
||||
closed bool
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
@@ -95,7 +99,7 @@ func NewResolvedResolver(ctx context.Context, logger logger.ContextLogger) (Reso
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) Start() error {
|
||||
t.updateStatus()
|
||||
t.updateStatus(t.ctx)
|
||||
t.interfaceCallback = t.interfaceMonitor.RegisterCallback(t.updateDefaultInterface)
|
||||
err := t.systemBus.BusObject().AddMatchSignal(
|
||||
"org.freedesktop.DBus",
|
||||
@@ -122,7 +126,17 @@ func (t *DBusResolvedResolver) Start() error {
|
||||
func (t *DBusResolvedResolver) Close() error {
|
||||
var closeErr error
|
||||
t.closeOnce.Do(func() {
|
||||
t.updateAccess.Lock()
|
||||
updateCancel := t.updateCancel
|
||||
t.updateCancel = nil
|
||||
t.updateAccess.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
t.updateRunAccess.Lock()
|
||||
t.closed = true
|
||||
serverSet := t.savedServerSet.Swap(nil)
|
||||
t.updateRunAccess.Unlock()
|
||||
if serverSet != nil {
|
||||
closeErr = serverSet.Close()
|
||||
}
|
||||
@@ -174,7 +188,7 @@ func (t *DBusResolvedResolver) Exchange(ctx context.Context, message *mDNS.Msg)
|
||||
if err == nil {
|
||||
return response, nil
|
||||
}
|
||||
t.updateStatus()
|
||||
t.updateStatus(t.ctx)
|
||||
refreshedServerSet := t.savedServerSet.Load()
|
||||
if refreshedServerSet == nil || refreshedServerSet == serverSet {
|
||||
return nil, err
|
||||
@@ -196,7 +210,7 @@ func (t *DBusResolvedResolver) ExchangeAsync(ctx context.Context, message *mDNS.
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
t.updateStatus()
|
||||
t.updateStatus(t.ctx)
|
||||
refreshedServerSet := t.savedServerSet.Load()
|
||||
if refreshedServerSet == nil || refreshedServerSet == serverSet {
|
||||
callback(nil, err)
|
||||
@@ -240,18 +254,44 @@ func (t *DBusResolvedResolver) loopUpdateStatus() {
|
||||
if !loaded || newOwner == "" {
|
||||
continue
|
||||
}
|
||||
t.updateStatus()
|
||||
t.postUpdateStatus()
|
||||
case "org.freedesktop.DBus.Properties.PropertiesChanged":
|
||||
if !shouldUpdateResolvedServerSet(signal) {
|
||||
continue
|
||||
}
|
||||
t.updateStatus()
|
||||
t.postUpdateStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) updateStatus() {
|
||||
serverSet, err := t.checkResolved(context.Background())
|
||||
func (t *DBusResolvedResolver) postUpdateStatus() {
|
||||
updateContext, updateCancel := context.WithCancel(t.ctx)
|
||||
t.updateAccess.Lock()
|
||||
previousCancel := t.updateCancel
|
||||
t.updateCancel = updateCancel
|
||||
t.updateAccess.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
go func() {
|
||||
defer updateCancel()
|
||||
t.updateStatus(updateContext)
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) updateStatus(ctx context.Context) {
|
||||
t.updateRunAccess.Lock()
|
||||
defer t.updateRunAccess.Unlock()
|
||||
if t.closed || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
serverSet, err := t.checkResolved(ctx)
|
||||
if t.closed || ctx.Err() != nil {
|
||||
if serverSet != nil {
|
||||
_ = serverSet.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
oldServerSet := t.savedServerSet.Swap(serverSet)
|
||||
if oldServerSet != nil {
|
||||
_ = oldServerSet.Close()
|
||||
@@ -291,7 +331,7 @@ func (t *DBusResolvedResolver) exchangeServerSet(ctx context.Context, message *m
|
||||
|
||||
func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*resolvedServerSet, error) {
|
||||
dbusObject := t.systemBus.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1")
|
||||
err := dbusObject.Call("org.freedesktop.DBus.Peer.Ping", 0).Err
|
||||
err := dbusObject.(*dbus.Object).CallWithContext(ctx, "org.freedesktop.DBus.Peer.Ping", 0).Err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -321,10 +361,18 @@ func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*resolvedServ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ctx.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
linkDNSEx, err := loadResolvedLinkDNSEx(linkObject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ctx.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
linkDNS, err := loadResolvedLinkDNS(linkObject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -570,5 +618,5 @@ func shouldUpdateResolvedServerSet(signal *dbus.Signal) bool {
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
|
||||
t.updateStatus()
|
||||
t.postUpdateStatus()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -120,7 +121,7 @@ func (p *linuxPlatformInterface) RequestPermissionForWIFIState() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *linuxPlatformInterface) ReadWIFIState() adapter.WIFIState {
|
||||
func (p *linuxPlatformInterface) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ func (p *windowsPlatformInterface) RequestPermissionForWIFIState() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *windowsPlatformInterface) ReadWIFIState() adapter.WIFIState {
|
||||
func (p *windowsPlatformInterface) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
func connectionRouter(ctx context.Context, network adapter.NetworkManager, trafficManager *trafficcontrol.Manager) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getConnections(ctx, trafficManager))
|
||||
r.Delete("/", closeAllConnections(network, trafficManager))
|
||||
r.Delete("/", closeAllConnections(ctx, network, trafficManager))
|
||||
r.Delete("/{id}", closeConnection(trafficManager))
|
||||
return r
|
||||
}
|
||||
@@ -170,10 +170,10 @@ func closeConnection(trafficManager *trafficcontrol.Manager) func(w http.Respons
|
||||
}
|
||||
}
|
||||
|
||||
func closeAllConnections(network adapter.NetworkManager, trafficManager *trafficcontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
|
||||
func closeAllConnections(ctx context.Context, network adapter.NetworkManager, trafficManager *trafficcontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
trafficManager.CloseAllConnections()
|
||||
network.ResetNetwork()
|
||||
network.ResetNetwork(ctx)
|
||||
render.NoContent(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ func (s *CommandServer) ResetNetwork() {
|
||||
if instance == nil || instance.Box() == nil {
|
||||
return
|
||||
}
|
||||
instance.Box().Network().ResetNetwork()
|
||||
instance.Box().Network().ResetNetwork(context.Background())
|
||||
}
|
||||
|
||||
func (s *CommandServer) UpdateWIFIState() {
|
||||
@@ -270,7 +270,7 @@ func (s *CommandServer) UpdateWIFIState() {
|
||||
if instance == nil || instance.Box() == nil {
|
||||
return
|
||||
}
|
||||
instance.Box().Network().UpdateWIFIState()
|
||||
instance.Box().Network().UpdateWIFIState(context.Background())
|
||||
}
|
||||
|
||||
type platformHandler CommandServer
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *platformInterfaceStub) UsePlatformWIFIMonitor() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) ReadWIFIState() adapter.WIFIState {
|
||||
func (s *platformInterfaceStub) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@@ -175,7 +176,7 @@ func (w *platformInterfaceWrapper) UsePlatformWIFIMonitor() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
|
||||
func (w *platformInterfaceWrapper) ReadWIFIState(ctx context.Context) adapter.WIFIState {
|
||||
wifiState := w.iif.ReadWIFIState()
|
||||
if wifiState == nil {
|
||||
return adapter.WIFIState{}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (i *Inbound) Start(stage adapter.StartStage) error {
|
||||
return i.listener.Start()
|
||||
}
|
||||
|
||||
func (i *Inbound) InterfaceUpdated() {
|
||||
func (i *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
i.udpNat.Purge()
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ func (h *Outbound) fetchMyAddresses() {
|
||||
h.myAddresses.Store(myAddresses)
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.fetchMyAddresses()
|
||||
if h.icmpPort != nil {
|
||||
h.icmpPort.Close()
|
||||
|
||||
@@ -45,6 +45,7 @@ type URLTest struct {
|
||||
tolerance uint16
|
||||
idleTimeout time.Duration
|
||||
group *URLTestGroup
|
||||
checkAccess sync.Mutex
|
||||
interruptExternalConnections bool
|
||||
}
|
||||
|
||||
@@ -114,14 +115,14 @@ func (s *URLTest) URLTest(ctx context.Context) (map[string]uint16, error) {
|
||||
}
|
||||
|
||||
func (s *URLTest) CheckOutbounds() {
|
||||
s.group.CheckOutbounds(true)
|
||||
s.group.CheckOutbounds(s.ctx, true)
|
||||
}
|
||||
|
||||
func (s *URLTest) PerformUpdateCheck() {
|
||||
s.group.performUpdateCheck()
|
||||
}
|
||||
|
||||
func (s *URLTest) InterfaceUpdated() {
|
||||
func (s *URLTest) InterfaceUpdated(ctx context.Context) {
|
||||
group := s.group
|
||||
if group == nil {
|
||||
return
|
||||
@@ -129,7 +130,14 @@ func (s *URLTest) InterfaceUpdated() {
|
||||
if group.pause.IsDevicePaused() || group.pause.IsNetworkPaused() {
|
||||
return
|
||||
}
|
||||
go group.CheckOutbounds(true)
|
||||
go func() {
|
||||
s.checkAccess.Lock()
|
||||
defer s.checkAccess.Unlock()
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
group.CheckOutbounds(ctx, true)
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
@@ -250,7 +258,7 @@ func (g *URLTestGroup) PostStart() {
|
||||
defer g.access.Unlock()
|
||||
g.started = true
|
||||
g.lastActive.Store(time.Now())
|
||||
go g.CheckOutbounds(false)
|
||||
go g.CheckOutbounds(g.ctx, false)
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) Touch() {
|
||||
@@ -330,7 +338,7 @@ func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
|
||||
func (g *URLTestGroup) loopCheck(ticker *time.Ticker, closeChan <-chan struct{}) {
|
||||
if time.Since(g.lastActive.Load()) > g.interval {
|
||||
g.lastActive.Store(time.Now())
|
||||
g.CheckOutbounds(false)
|
||||
g.CheckOutbounds(g.ctx, false)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
@@ -349,12 +357,12 @@ func (g *URLTestGroup) loopCheck(ticker *time.Ticker, closeChan <-chan struct{})
|
||||
g.access.Unlock()
|
||||
return
|
||||
}
|
||||
g.CheckOutbounds(false)
|
||||
g.CheckOutbounds(g.ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) CheckOutbounds(force bool) {
|
||||
_, _ = g.urlTest(g.ctx, force)
|
||||
func (g *URLTestGroup) CheckOutbounds(ctx context.Context, force bool) {
|
||||
_, _ = g.urlTest(ctx, force)
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) URLTest(ctx context.Context) (map[string]uint16, error) {
|
||||
@@ -391,7 +399,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
||||
continue
|
||||
}
|
||||
b.Go(realTag, func() (any, error) {
|
||||
testCtx, cancel := context.WithTimeout(g.ctx, C.TCPTimeout)
|
||||
testCtx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
|
||||
defer cancel()
|
||||
testChan := make(chan urlTestResult, 1)
|
||||
go func() {
|
||||
|
||||
@@ -115,7 +115,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return h.client.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.client.CloseWithError(E.New("network changed"))
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
return h.service.Start(packetConn)
|
||||
}
|
||||
|
||||
func (h *Inbound) InterfaceUpdated() {
|
||||
func (h *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.service.Reset()
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return h.client.ListenPacket(ctx)
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.client.CloseWithError(E.New("network changed"))
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return h.uotClient.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.client.Engine().CloseAllConnections()
|
||||
}
|
||||
|
||||
|
||||
@@ -486,7 +486,7 @@ func (e *Endpoint) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Endpoint) InterfaceUpdated() {
|
||||
func (e *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
e.client.RestartSession()
|
||||
}
|
||||
|
||||
|
||||
@@ -658,7 +658,7 @@ func (c *ClientEndpoint) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) InterfaceUpdated() {
|
||||
func (c *ClientEndpoint) InterfaceUpdated(ctx context.Context) {
|
||||
c.client.RestartSession()
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ func (t *TProxy) Start(stage adapter.StartStage) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *TProxy) InterfaceUpdated() {
|
||||
func (t *TProxy) InterfaceUpdated(ctx context.Context) {
|
||||
t.udpNat.Purge()
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ func (h *Outbound) MultiplexEnabled() bool {
|
||||
return h.multiplexDialer != nil
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
if h.multiplexDialer != nil {
|
||||
h.multiplexDialer.Reset()
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return packetConn, nil
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.client.Reset()
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ func (s *Outbound) connect(ctx context.Context) (client *ssh.Client, err error)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (s *Outbound) InterfaceUpdated() {
|
||||
func (s *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
common.Close(s.clientConn)
|
||||
}
|
||||
|
||||
|
||||
@@ -740,7 +740,7 @@ func (t *Endpoint) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Endpoint) InterfaceUpdated() {
|
||||
func (t *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
if !t.started.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (h *Outbound) MultiplexEnabled() bool {
|
||||
return h.multiplexDialer != nil
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
if h.transport != nil {
|
||||
h.transport.Close()
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
_ = h.client.CloseWithError(E.New("network changed"))
|
||||
}
|
||||
|
||||
|
||||
@@ -505,7 +505,7 @@ func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) {
|
||||
t.routeExcludeAddressSet = nil
|
||||
}
|
||||
|
||||
func (t *Inbound) InterfaceUpdated() {
|
||||
func (t *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
tunStack := t.tunStack
|
||||
if tunStack != nil {
|
||||
tunStack.ResetNetwork()
|
||||
|
||||
@@ -133,7 +133,7 @@ func (h *Outbound) MultiplexEnabled() bool {
|
||||
return h.multiplexDialer != nil
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
if h.transport != nil {
|
||||
h.transport.Close()
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ func (h *Outbound) MultiplexEnabled() bool {
|
||||
return h.multiplexDialer != nil
|
||||
}
|
||||
|
||||
func (h *Outbound) InterfaceUpdated() {
|
||||
func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
if h.transport != nil {
|
||||
h.transport.Close()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -42,6 +43,7 @@ type Endpoint struct {
|
||||
logger logger.ContextLogger
|
||||
localAddresses []netip.Prefix
|
||||
endpoint *wireguard.Endpoint
|
||||
bindAccess sync.Mutex
|
||||
started atomic.Bool
|
||||
}
|
||||
|
||||
@@ -145,14 +147,25 @@ func (w *Endpoint) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
|
||||
func (w *Endpoint) Close() error {
|
||||
w.bindAccess.Lock()
|
||||
w.started.Store(false)
|
||||
w.bindAccess.Unlock()
|
||||
return w.endpoint.Close()
|
||||
}
|
||||
|
||||
func (w *Endpoint) InterfaceUpdated() {
|
||||
func (w *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
if !w.started.Load() {
|
||||
return
|
||||
}
|
||||
go w.updateBind(ctx)
|
||||
}
|
||||
|
||||
func (w *Endpoint) updateBind(ctx context.Context) {
|
||||
w.bindAccess.Lock()
|
||||
defer w.bindAccess.Unlock()
|
||||
if ctx.Err() != nil || !w.started.Load() {
|
||||
return
|
||||
}
|
||||
err := w.endpoint.BindUpdate()
|
||||
if err != nil {
|
||||
w.logger.Error(E.Cause(err, "update bind"))
|
||||
|
||||
+98
-39
@@ -34,32 +34,37 @@ 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
|
||||
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
|
||||
interfaceUpdateAccess sync.Mutex
|
||||
interfaceUpdateCancel context.CancelFunc
|
||||
interfaceUpdateRunAccess sync.Mutex
|
||||
powerUpdateAccess sync.Mutex
|
||||
powerUpdateCancel context.CancelFunc
|
||||
started bool
|
||||
}
|
||||
|
||||
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options option.RouteOptions, dnsOptions option.DNSOptions) (*NetworkManager, error) {
|
||||
@@ -251,6 +256,14 @@ 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 {
|
||||
@@ -455,19 +468,19 @@ func (r *NetworkManager) onWIFIStateChanged(state adapter.WIFIState) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetworkManager) UpdateWIFIState() {
|
||||
func (r *NetworkManager) UpdateWIFIState(ctx context.Context) {
|
||||
var state adapter.WIFIState
|
||||
if r.wifiMonitor != nil {
|
||||
state = r.wifiMonitor.ReadWIFIState()
|
||||
state = r.wifiMonitor.ReadWIFIState(ctx)
|
||||
} else if r.platformInterface != nil && r.platformInterface.UsePlatformWIFIMonitor() {
|
||||
state = r.platformInterface.ReadWIFIState()
|
||||
state = r.platformInterface.ReadWIFIState(ctx)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
r.onWIFIStateChanged(state)
|
||||
}
|
||||
|
||||
func (r *NetworkManager) ResetNetwork() {
|
||||
func (r *NetworkManager) ResetNetwork(ctx context.Context) {
|
||||
if r.connectionManager != nil {
|
||||
r.connectionManager.CloseAll()
|
||||
}
|
||||
@@ -475,21 +488,21 @@ func (r *NetworkManager) ResetNetwork() {
|
||||
for _, endpoint := range r.endpoint.Endpoints() {
|
||||
listener, isListener := endpoint.(adapter.InterfaceUpdateListener)
|
||||
if isListener {
|
||||
listener.InterfaceUpdated()
|
||||
listener.InterfaceUpdated(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
for _, inbound := range r.inbound.Inbounds() {
|
||||
listener, isListener := inbound.(adapter.InterfaceUpdateListener)
|
||||
if isListener {
|
||||
listener.InterfaceUpdated()
|
||||
listener.InterfaceUpdated(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
for _, outbound := range r.outbound.Outbounds() {
|
||||
listener, isListener := outbound.(adapter.InterfaceUpdateListener)
|
||||
if isListener {
|
||||
listener.InterfaceUpdated()
|
||||
listener.InterfaceUpdated(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,8 +515,27 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa
|
||||
r.logger.Error("missing default interface")
|
||||
return
|
||||
}
|
||||
|
||||
r.pauseManager.NetworkWake()
|
||||
updateContext, updateCancel := context.WithCancel(r.ctx)
|
||||
r.interfaceUpdateAccess.Lock()
|
||||
previousCancel := r.interfaceUpdateCancel
|
||||
r.interfaceUpdateCancel = updateCancel
|
||||
r.interfaceUpdateAccess.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
go func() {
|
||||
defer updateCancel()
|
||||
r.updateInterface(updateContext, defaultInterface)
|
||||
}()
|
||||
}
|
||||
|
||||
func (r *NetworkManager) updateInterface(ctx context.Context, defaultInterface *control.Interface) {
|
||||
r.interfaceUpdateRunAccess.Lock()
|
||||
defer r.interfaceUpdateRunAccess.Unlock()
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
var options []string
|
||||
options = append(options, F.ToString("index ", defaultInterface.Index))
|
||||
if C.IsAndroid && r.platformInterface == nil {
|
||||
@@ -531,20 +563,26 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa
|
||||
}
|
||||
}
|
||||
r.logger.Info("updated default interface ", defaultInterface.Name, ", ", strings.Join(options, ", "))
|
||||
r.UpdateWIFIState()
|
||||
r.UpdateWIFIState(ctx)
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
r.updateNetworkEnvironment()
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if !r.started {
|
||||
return
|
||||
}
|
||||
r.ResetNetwork()
|
||||
r.ResetNetwork(ctx)
|
||||
}
|
||||
|
||||
func (r *NetworkManager) notifyWindowsPowerEvent(event int) {
|
||||
switch event {
|
||||
case winpowrprof.EVENT_SUSPEND:
|
||||
r.pauseManager.DevicePause()
|
||||
r.ResetNetwork()
|
||||
r.cancelPowerUpdate()
|
||||
r.ResetNetwork(r.ctx)
|
||||
case winpowrprof.EVENT_RESUME:
|
||||
if !r.pauseManager.IsDevicePaused() {
|
||||
return
|
||||
@@ -552,7 +590,28 @@ func (r *NetworkManager) notifyWindowsPowerEvent(event int) {
|
||||
fallthrough
|
||||
case winpowrprof.EVENT_RESUME_AUTOMATIC:
|
||||
r.pauseManager.DeviceWake()
|
||||
r.ResetNetwork()
|
||||
updateContext, updateCancel := context.WithCancel(r.ctx)
|
||||
r.powerUpdateAccess.Lock()
|
||||
previousCancel := r.powerUpdateCancel
|
||||
r.powerUpdateCancel = updateCancel
|
||||
r.powerUpdateAccess.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
go func() {
|
||||
defer updateCancel()
|
||||
r.ResetNetwork(updateContext)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetworkManager) cancelPowerUpdate() {
|
||||
r.powerUpdateAccess.Lock()
|
||||
previousCancel := r.powerUpdateCancel
|
||||
r.powerUpdateCancel = nil
|
||||
r.powerUpdateAccess.Unlock()
|
||||
if previousCancel != nil {
|
||||
previousCancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package oomkiller
|
||||
|
||||
import (
|
||||
"context"
|
||||
runtimeDebug "runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -203,14 +204,14 @@ func (t *adaptiveTimer) poll() {
|
||||
t.logger.Warn("memory growth rate critical (report only), usage: ", byteformats.FormatMemoryBytes(sample.usage), t.logDetails(sample))
|
||||
} else {
|
||||
t.logger.Error("memory growth rate critical, usage: ", byteformats.FormatMemoryBytes(sample.usage), t.logDetails(sample), ", resetting network")
|
||||
t.network.ResetNetwork()
|
||||
t.network.ResetNetwork(context.Background())
|
||||
}
|
||||
} else {
|
||||
if t.killerDisabled {
|
||||
t.logger.Warn("memory threshold reached (report only), usage: ", byteformats.FormatMemoryBytes(sample.usage), t.logDetails(sample))
|
||||
} else {
|
||||
t.logger.Error("memory threshold reached, usage: ", byteformats.FormatMemoryBytes(sample.usage), t.logDetails(sample), ", resetting network")
|
||||
t.network.ResetNetwork()
|
||||
t.network.ResetNetwork(context.Background())
|
||||
}
|
||||
}
|
||||
badCleanup()
|
||||
|
||||
Reference in New Issue
Block a user