Skip to content

DNS mode: reduce upstream refresh latency after WiFi switch #105

Description

@flyhigher139

背景

Issue #103 修了 upstream 不跟随 WiFi 切换的 bug,但 hot-swap 仍然依赖 60 秒一次的 polling。最坏情况:用户在第 0 秒切 WiFi,要等到第 60 秒 polling tick 才生效。这期间所有 DNS 查询要么走旧 upstream(可能 timeout / 拿到错的 IP),要么落在 8.8.8.8 / 1.1.1.1(如果 hickory rotate 命中公共 DNS)。

已完成:Polling 间隔降到 15s(option 1)

PR #104 第三个 commit 把 UPSTREAM_REFRESH_INTERVALDuration::from_secs(60) 改成 Duration::from_secs(15)

最坏延时从 60s 降到 15s。每次 tick 调用 networksetup + ipconfig 共 4 个 shell 命令,加起来 < 10ms,对 CPU / 电量影响可忽略。

后续可选优化

Option 2: SCDynamicStore 事件驱动(< 1s 延时)

监听 macOS SystemConfigurationState:/Network/Interface/.*/IPv4State:/Network/Global/IPv4 变化,WiFi 一切换立刻回调。

实现要点:

  • 新增 FFI 依赖:objc2-system-configuration(更现代)或 core-foundation
  • C 回调桥到 tokio:用 mpsc::Sender 投递到 refresh task
  • run_upstream_refresh_looptokio::select! 增加一个 notify_one 分支,收到事件立刻重新拉取 upstream 并 hot-swap
  • macOS-only;Windows / Linux 走 15s polling 兜底
  • 预计 +150 行,单测能覆盖大部分,集成测要 macOS 实机

参考 API:

SCDynamicStoreCreate(...)
SCDynamicStoreSetNotificationKeys(keys: ["State:/Network/Interface/.*/IPv4", "State:/Network/Global/IPv4"])
SCDynamicStoreSetCallback(...)

Option 3: Hybrid — SCDynamicStore + Notify wakeup + 60s polling 兜底

保留 15s polling 的安全网(兜底、防漏事件),加一个 SCDynamicStore listener 在事件触发时 refresh_shutdown.notify_one() 提前唤醒 refresh loop。比 Option 2 更稳(不会漏事件),复杂度略高。

推荐路径

短期:当前 15s polling 已经够用。
中长期:上 Option 3(最稳),或者如果觉得依赖太重直接 Option 2(最简)。

关联

验证步骤

启用 DNS 模式 → 切 WiFi → 看日志:

INFO  mhost_dns::server: DNS upstream refresh tick: change detected <old> -> <new>
INFO  mhost_dns::server: DNS server upstream hot-swapped: <old> -> <new> (network change applied)

两条 INFO 之间的间隔应 ≤ 15s(option 1)。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions