Commit b4d003f0 authored by Mygod's avatar Mygod

Refine LocalSocketListener

parent 2e289597
...@@ -23,16 +23,18 @@ package com.github.shadowsocks.bg ...@@ -23,16 +23,18 @@ package com.github.shadowsocks.bg
import android.net.LocalServerSocket import android.net.LocalServerSocket
import android.net.LocalSocket import android.net.LocalSocket
import android.net.LocalSocketAddress import android.net.LocalSocketAddress
import android.system.Os
import android.system.OsConstants
import com.github.shadowsocks.utils.printLog import com.github.shadowsocks.utils.printLog
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
abstract class LocalSocketListener(protected val tag: String) : Thread(tag) { abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name), AutoCloseable {
init { private val localSocket = LocalSocket().apply {
setUncaughtExceptionHandler { _, t -> printLog(t) } socketFile.delete() // It's a must-have to close and reuse previous local socket.
bind(LocalSocketAddress(socketFile.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM))
} }
private val serverSocket = LocalServerSocket(localSocket.fileDescriptor)
protected abstract val socketFile: File
@Volatile @Volatile
private var running = true private var running = true
...@@ -40,29 +42,21 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) { ...@@ -40,29 +42,21 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) {
* Inherited class do not need to close input/output streams as they will be closed automatically. * Inherited class do not need to close input/output streams as they will be closed automatically.
*/ */
protected abstract fun accept(socket: LocalSocket) protected abstract fun accept(socket: LocalSocket)
final override fun run() { final override fun run() = localSocket.use {
socketFile.delete() // It's a must-have to close and reuse previous local socket. while (running) {
LocalSocket().use { localSocket -> try {
val serverSocket = try { serverSocket.accept().use { accept(it) }
localSocket.bind(LocalSocketAddress(socketFile.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM))
LocalServerSocket(localSocket.fileDescriptor)
} catch (e: IOException) { } catch (e: IOException) {
printLog(e) if (running) printLog(e)
return continue
}
while (running) {
try {
serverSocket.accept()
} catch (e: IOException) {
printLog(e)
continue
}?.use(this::accept)
} }
} }
} }
fun stopThread() { override fun close() {
running = false running = false
interrupt() // see also: https://issuetracker.google.com/issues/36945762#comment15
Os.shutdown(localSocket.fileDescriptor, OsConstants.SHUT_RDWR)
join()
} }
} }
...@@ -23,33 +23,26 @@ package com.github.shadowsocks.bg ...@@ -23,33 +23,26 @@ package com.github.shadowsocks.bg
import android.net.LocalSocket import android.net.LocalSocket
import android.os.SystemClock import android.os.SystemClock
import com.github.shadowsocks.aidl.TrafficStats import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.utils.printLog
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
class TrafficMonitor(statFile: File) : AutoCloseable { class TrafficMonitor(statFile: File) : AutoCloseable {
private val thread = object : LocalSocketListener("TrafficMonitor") { private val thread = object : LocalSocketListener("TrafficMonitor", statFile) {
override val socketFile = statFile
override fun accept(socket: LocalSocket) { override fun accept(socket: LocalSocket) {
try { val buffer = ByteArray(16)
val buffer = ByteArray(16) if (socket.inputStream.read(buffer) != 16) throw IOException("Unexpected traffic stat length")
if (socket.inputStream.read(buffer) != 16) throw IOException("Unexpected traffic stat length") val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN) val tx = stat.getLong(0)
val tx = stat.getLong(0) val rx = stat.getLong(8)
val rx = stat.getLong(8) if (current.txTotal != tx) {
if (current.txTotal != tx) { current.txTotal = tx
current.txTotal = tx dirty = true
dirty = true }
} if (current.rxTotal != rx) {
if (current.rxTotal != rx) { current.rxTotal = rx
current.rxTotal = rx dirty = true
dirty = true
}
} catch (e: IOException) {
printLog(e)
} }
} }
}.apply { start() } }.apply { start() }
...@@ -57,7 +50,6 @@ class TrafficMonitor(statFile: File) : AutoCloseable { ...@@ -57,7 +50,6 @@ class TrafficMonitor(statFile: File) : AutoCloseable {
val current = TrafficStats() val current = TrafficStats()
var out = TrafficStats() var out = TrafficStats()
private var timestampLast = 0L private var timestampLast = 0L
@Volatile
private var dirty = false private var dirty = false
fun requestUpdate(): Pair<TrafficStats, Boolean> { fun requestUpdate(): Pair<TrafficStats, Boolean> {
...@@ -87,5 +79,5 @@ class TrafficMonitor(statFile: File) : AutoCloseable { ...@@ -87,5 +79,5 @@ class TrafficMonitor(statFile: File) : AutoCloseable {
return Pair(out, updated) return Pair(out, updated)
} }
override fun close() = thread.stopThread() override fun close() = thread.close()
} }
...@@ -78,10 +78,9 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -78,10 +78,9 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override fun close() = Os.close(fd) override fun close() = Os.close(fd)
} }
private inner class ProtectWorker : LocalSocketListener("ShadowsocksVpnThread") { private inner class ProtectWorker :
override val socketFile: File = File(Core.deviceStorage.noBackupFilesDir, "protect_path") LocalSocketListener("ShadowsocksVpnThread", File(Core.deviceStorage.noBackupFilesDir, "protect_path")) {
override fun accept(socket: LocalSocket) {
override fun accept(socket: LocalSocket) = try {
socket.inputStream.read() socket.inputStream.read()
val fd = socket.ancillaryFileDescriptors!!.single()!! val fd = socket.ancillaryFileDescriptors!!.single()!!
CloseableFd(fd).use { CloseableFd(fd).use {
...@@ -96,8 +95,6 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -96,8 +95,6 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
} else protect(getInt.invoke(fd) as Int) } else protect(getInt.invoke(fd) as Int)
}) 0 else 1) }) 0 else 1)
} }
} catch (e: IOException) {
printLog(e)
} }
} }
inner class NullConnectionException : NullPointerException() { inner class NullConnectionException : NullPointerException() {
...@@ -146,7 +143,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -146,7 +143,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
connectivity.unregisterNetworkCallback(defaultNetworkCallback) connectivity.unregisterNetworkCallback(defaultNetworkCallback)
listeningForDefaultNetwork = false listeningForDefaultNetwork = false
} }
worker?.stopThread() worker?.close()
worker = null worker = null
super.killProcesses() super.killProcesses()
conn?.close() conn?.close()
...@@ -164,9 +161,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -164,9 +161,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
} }
override suspend fun startProcesses() { override suspend fun startProcesses() {
val worker = ProtectWorker() worker = ProtectWorker().apply { start() }
worker.start()
this.worker = worker
super.startProcesses() super.startProcesses()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment