From c573a68ee17cd3ade64c95e90cfd2cc85d86e841 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 3 Oct 2018 14:34:55 +0800 Subject: [PATCH] Prevent creating 2 ip link monitors --- .../net/monitor/InterfaceMonitor.kt | 36 +++------------- .../vpnhotspot/net/monitor/IpLinkMonitor.kt | 43 +++++++++++++++++++ 2 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/IpLinkMonitor.kt diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/InterfaceMonitor.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/InterfaceMonitor.kt index 2eaa687a..dec5c7b1 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/InterfaceMonitor.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/InterfaceMonitor.kt @@ -3,26 +3,6 @@ package be.mygod.vpnhotspot.net.monitor import be.mygod.vpnhotspot.App.Companion.app class InterfaceMonitor(val iface: String) : UpstreamMonitor() { - companion object { - /** - * Based on: https://android.googlesource.com/platform/external/iproute2/+/70556c1/ip/ipaddress.c#1053 - */ - private val parser = "^(Deleted )?-?\\d+: ([^:@]+)".toRegex() - } - - private inner class IpLinkMonitor : IpMonitor() { - override val monitoredObject: String get() = "link" - - override fun processLine(line: String) { - val match = parser.find(line) ?: return - if (match.groupValues[2] != iface) return - setPresent(match.groupValues[1].isEmpty()) - } - - override fun processLines(lines: Sequence) = - setPresent(lines.any { parser.find(it)?.groupValues?.get(2) == iface }) - } - private fun setPresent(present: Boolean) = synchronized(this) { val old = currentIface != null if (present == old) return @@ -33,7 +13,7 @@ class InterfaceMonitor(val iface: String) : UpstreamMonitor() { } else callbacks.forEach { it.onLost() } } - private var monitor: IpLinkMonitor? = null + private var registered = false override var currentIface: String? = null private set override val currentLinkProperties get() = app.connectivity.allNetworks @@ -41,18 +21,14 @@ class InterfaceMonitor(val iface: String) : UpstreamMonitor() { .singleOrNull { it?.interfaceName == iface } override fun registerCallbackLocked(callback: Callback) { - var monitor = monitor - if (monitor == null) { - monitor = IpLinkMonitor() - this.monitor = monitor - monitor.run() + if (!registered) { + IpLinkMonitor.registerCallback(this, iface, this::setPresent) + registered = true } else if (currentIface != null) callback.onAvailable(iface, currentDns) } override fun destroyLocked() { - val monitor = monitor ?: return - this.monitor = null - currentIface = null - monitor.destroy() + IpLinkMonitor.unregisterCallback(this) + registered = false } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/IpLinkMonitor.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/IpLinkMonitor.kt new file mode 100644 index 00000000..972b95a3 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/IpLinkMonitor.kt @@ -0,0 +1,43 @@ +package be.mygod.vpnhotspot.net.monitor + +class IpLinkMonitor private constructor() : IpMonitor() { + companion object { + /** + * Based on: https://android.googlesource.com/platform/external/iproute2/+/70556c1/ip/ipaddress.c#1053 + */ + private val parser = "^(Deleted )?-?\\d+: ([^:@]+)".toRegex() + + private val callbacks = HashMap Unit>>() + private var instance: IpLinkMonitor? = null + + fun registerCallback(owner: Any, iface: String, callback: (Boolean) -> Unit) { + check(callbacks.put(owner, Pair(iface, callback)) == null) + var monitor = instance + if (monitor == null) { + monitor = IpLinkMonitor() + instance = monitor + } + monitor.flush() + } + fun unregisterCallback(owner: Any) { + if (callbacks.remove(owner) == null || callbacks.isNotEmpty()) return + instance?.destroy() + instance = null + } + } + + override val monitoredObject: String get() = "link" + + override fun processLine(line: String) { + val match = parser.find(line) ?: return + val iface = match.groupValues[2] + val present = match.groupValues[1].isEmpty() + for ((target, callback) in callbacks.values) if (target == iface) callback(present) + } + + override fun processLines(lines: Sequence) { + val present = HashSet() + for (it in lines) present.add((parser.find(it) ?: continue).groupValues[2]) + callbacks.values.forEach { (iface, callback) -> callback(present.contains(iface)) } + } +}