Prevent creating 2 ip link monitors

This commit is contained in:
Mygod
2018-10-03 14:34:55 +08:00
parent a4e69c5a9b
commit c573a68ee1
2 changed files with 49 additions and 30 deletions

View File

@@ -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<String>) =
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
}
}

View File

@@ -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<Any, Pair<String, (Boolean) -> 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<String>) {
val present = HashSet<String>()
for (it in lines) present.add((parser.find(it) ?: continue).groupValues[2])
callbacks.values.forEach { (iface, callback) -> callback(present.contains(iface)) }
}
}