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:
+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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user