Add synchronization for RoutingManager

This commit is contained in:
Mygod
2020-06-12 00:26:43 -04:00
parent 37f46e0202
commit 8d6d4a6c6e
2 changed files with 24 additions and 13 deletions

View File

@@ -24,10 +24,13 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
} }
set(value) = app.pref.edit().putString(KEY_MASQUERADE_MODE, value.name).apply() set(value) = app.pref.edit().putString(KEY_MASQUERADE_MODE, value.name).apply()
/**
* Thread safety: needs protection by companion object!
*/
private val active = mutableMapOf<String, RoutingManager>() private val active = mutableMapOf<String, RoutingManager>()
fun clean(reinit: Boolean = true) { fun clean(reinit: Boolean = true) = synchronized(this) {
if (!reinit && active.isEmpty()) return if (!reinit && active.isEmpty()) return@synchronized
for (manager in active.values) manager.routing?.stop() for (manager in active.values) manager.routing?.stop()
try { try {
Routing.clean() Routing.clean()
@@ -36,7 +39,7 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
SmartSnackbar.make(e).show() SmartSnackbar.make(e).show()
return return
} }
if (reinit) for (manager in active.values) manager.initRouting() if (reinit) for (manager in active.values) manager.initRoutingLocked()
} }
} }
@@ -52,21 +55,28 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
} }
} }
val started get() = active[downstream] === this var started = false
private set
/**
* Thread safety: needs protection by companion object!
*/
private var routing: Routing? = null private var routing: Routing? = null
fun start() = when (val other = active.putIfAbsent(downstream, this)) { fun start() = synchronized(RoutingManager) {
null -> { started = true
if (isWifi) WifiDoubleLock.acquire(this) when (val other = active.putIfAbsent(downstream, this)) {
initRouting() null -> {
if (isWifi) WifiDoubleLock.acquire(this)
initRoutingLocked()
}
this -> true // already started
else -> error("Double routing detected for $downstream from $caller != ${other.caller}")
} }
this -> true // already started
else -> error("Double routing detected for $downstream from $caller != ${other.caller}")
} }
open fun ifaceHandler(iface: NetworkInterface) { } open fun ifaceHandler(iface: NetworkInterface) { }
private fun initRouting() = try { private fun initRoutingLocked() = try {
routing = Routing(caller, downstream, this::ifaceHandler).apply { routing = Routing(caller, downstream, this::ifaceHandler).apply {
try { try {
configure() configure()
@@ -85,7 +95,8 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
protected abstract fun Routing.configure() protected abstract fun Routing.configure()
fun stop() { fun stop() = synchronized(RoutingManager) {
started = false
if (active.remove(downstream, this)) { if (active.remove(downstream, this)) {
if (isWifi) WifiDoubleLock.release(this) if (isWifi) WifiDoubleLock.release(this)
routing?.revert() routing?.revert()

View File

@@ -331,6 +331,7 @@ class Routing(private val caller: Any, private val downstream: String,
IpNeighbourMonitor.unregisterCallback(this) IpNeighbourMonitor.unregisterCallback(this)
FallbackUpstreamMonitor.unregisterCallback(fallbackUpstream) FallbackUpstreamMonitor.unregisterCallback(fallbackUpstream)
UpstreamMonitor.unregisterCallback(upstream) UpstreamMonitor.unregisterCallback(upstream)
Timber.i("Stopped routing for $downstream by $caller")
} }
fun commit() { fun commit() {
@@ -345,7 +346,6 @@ class Routing(private val caller: Any, private val downstream: String,
} }
fun revert() { fun revert() {
stop() stop()
Timber.i("Stopped routing for $downstream by $caller")
TrafficRecorder.update() // record stats before exiting to prevent stats losing TrafficRecorder.update() // record stats before exiting to prevent stats losing
synchronized(this) { clients.values.forEach { it.close() } } synchronized(this) { clients.values.forEach { it.close() } }
currentDns?.transaction?.revert() currentDns?.transaction?.revert()