Handle network update callbacks in background

This commit is contained in:
世界
2026-08-30 17:41:46 +08:00
parent cfddedb3da
commit 6720a27109
46 changed files with 382 additions and 134 deletions
+39 -11
View File
@@ -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
+57 -9
View File
@@ -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()
}