Lift double routing detection out of Routing

This commit is contained in:
Mygod
2019-03-09 01:46:01 -05:00
parent b9292b8be4
commit aedba90196
5 changed files with 24 additions and 31 deletions

View File

@@ -3,7 +3,8 @@ package be.mygod.vpnhotspot
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.Routing
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
import be.mygod.vpnhotspot.util.Event0
import be.mygod.vpnhotspot.util.putIfAbsentCompat
import be.mygod.vpnhotspot.util.removeCompat
import be.mygod.vpnhotspot.widget.SmartSnackbar
import timber.log.Timber
@@ -18,11 +19,10 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
}
set(value) = app.pref.edit().putString(KEY_MASQUERADE_MODE, value.name).apply()
private val onPreCleanRoutings = Event0()
private val onRoutingsCleaned = Event0()
private val active = mutableMapOf<String, RoutingManager>()
fun clean() {
onPreCleanRoutings()
for (manager in active.values) manager.routing?.stop()
val cleaned = try {
Routing.clean()
true
@@ -31,7 +31,7 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
SmartSnackbar.make(e).show()
false
}
if (cleaned) onRoutingsCleaned()
if (cleaned) for (manager in active.values) manager.initRouting()
}
}
@@ -47,18 +47,16 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
}
}
var started = false
val started get() = active[downstream] === this
private var routing: Routing? = null
init {
if (isWifi) WifiDoubleLock.acquire(this)
}
fun start(): Boolean {
check(!started)
started = true
onPreCleanRoutings[this] = { routing?.stop() }
onRoutingsCleaned[this] = { initRouting() }
return initRouting()
fun start() = when (active.putIfAbsentCompat(downstream, this)) {
null -> initRouting()
this -> true // already started
else -> throw IllegalStateException("Double routing detected from $caller")
}
private fun initRouting() = try {
@@ -81,11 +79,7 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
protected abstract fun Routing.configure()
fun stop() {
if (!started) return
routing?.revert()
onPreCleanRoutings -= this
onRoutingsCleaned -= this
started = false
if (active.removeCompat(downstream, this)) routing?.revert()
}
fun destroy() {

View File

@@ -50,7 +50,7 @@ class TetheringService : IpNeighbourMonitoringService() {
val toRemove = downstreams.toMutableMap() // make a copy
for (iface in TetheringManager.getTetheredIfaces(extras)) {
val downstream = toRemove.remove(iface) ?: continue
if (downstream.monitor && !downstream.started) downstream.start()
if (downstream.monitor) downstream.start()
}
for ((iface, downstream) in toRemove) {
if (downstream.monitor) downstream.stop() else downstreams.remove(iface)?.destroy()

View File

@@ -42,11 +42,6 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
*/
val IPTABLES = if (Build.VERSION.SDK_INT >= 26) "iptables -w 1" else "iptables -w"
/**
* For debugging: check that we do not start a Routing for the same interface twice.
*/
private var downstreams = mutableSetOf<String>()
fun clean() {
TrafficRecorder.clean()
RootSession.use {
@@ -60,7 +55,6 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
it.execQuiet("while ip rule del priority $RULE_PRIORITY_UPSTREAM; do done")
it.execQuiet("while ip rule del priority $RULE_PRIORITY_UPSTREAM_FALLBACK; do done")
}
downstreams.clear()
}
private fun RootSession.Transaction.iptables(command: String, revert: String) {
@@ -89,10 +83,6 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
override val message: String get() = app.getString(R.string.exception_interface_not_found)
}
init {
check(downstreams.add(downstream)) { "Double routing detected from $caller" }
}
private val hostAddress = try {
NetworkInterface.getByName(downstream)!!.interfaceAddresses!!.asSequence().single { it.address is Inet4Address }
} catch (e: Exception) {
@@ -314,6 +304,5 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
fallbackUpstream.subrouting?.transaction?.revert()
upstream.subrouting?.transaction?.revert()
transaction.revert()
check(downstreams.remove(downstream)) { "Double reverting detected from $caller" }
}
}

View File

@@ -9,6 +9,7 @@ import be.mygod.vpnhotspot.room.TrafficRecord
import be.mygod.vpnhotspot.util.Event2
import be.mygod.vpnhotspot.util.RootSession
import be.mygod.vpnhotspot.util.parseNumericAddress
import be.mygod.vpnhotspot.util.putIfAbsentCompat
import be.mygod.vpnhotspot.widget.SmartSnackbar
import timber.log.Timber
import java.net.InetAddress
@@ -28,7 +29,7 @@ object TrafficRecorder {
AppDatabase.instance.trafficRecordDao.insert(record)
synchronized(this) {
DebugHelper.log(TAG, "Registering $ip%$downstream")
check(records.put(Pair(ip, downstream), record) == null)
check(records.putIfAbsentCompat(Pair(ip, downstream), record) == null)
scheduleUpdateLocked()
}
}

View File

@@ -91,5 +91,14 @@ fun Context.stopAndUnbind(connection: ServiceConnection) {
unbindService(connection)
}
fun <K, V> HashMap<K, V>.computeIfAbsentCompat(key: K, value: () -> V) = if (Build.VERSION.SDK_INT >= 26)
fun <K, V> MutableMap<K, V>.computeIfAbsentCompat(key: K, value: () -> V) = if (Build.VERSION.SDK_INT >= 26)
computeIfAbsent(key) { value() } else this[key] ?: value().also { put(key, it) }
fun <K, V> MutableMap<K, V>.putIfAbsentCompat(key: K, value: V) = if (Build.VERSION.SDK_INT >= 24)
putIfAbsent(key, value) else this[key] ?: put(key, value)
fun <K, V> MutableMap<K, V>.removeCompat(key: K, value: V) = if (Build.VERSION.SDK_INT >= 24) remove(key, value) else {
val curValue = get(key)
if (curValue === value && (curValue != null || containsKey(key))) {
remove(key)
true
} else false
}