changed scope.cancel, 当协程上下文被取消,会将资源做对应处理

This commit is contained in:
asxalex 2025-07-15 16:36:50 +08:00
parent fa2453a733
commit 867fb5ca72
5 changed files with 96 additions and 61 deletions

View File

@ -24,6 +24,7 @@ import com.jihe.punchnet.sdlan.network.DeviceConfig
import com.jihe.punchnet.sdlan.network.IfaceTun
import com.jihe.punchnet.sdlan.network.RouteDetail
import com.jihe.punchnet.sdlan.network.RouteTable
import com.jihe.punchnet.sdlan.network.StartStopChanInfo
import com.jihe.punchnet.sdlan.network.cidrToRouteDetail
import com.jihe.punchnet.sdlan.network.ipInt2ByteArray
import com.jihe.punchnet.sdlan.network.maskIPToDigit
@ -33,6 +34,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.FileInputStream
@ -50,6 +52,7 @@ class PunchnetService : VpnService() , IfaceTun {
private val serviceLock = Any()
private val isRunning = AtomicBoolean(false)
private val start_stop_channel = Channel<StartStopChanInfo>(100)
var input: FileInputStream? = null
var output: FileOutputStream? = null
@ -64,6 +67,10 @@ class PunchnetService : VpnService() , IfaceTun {
const val ACTION_DISCONNECT = "com.jihe.punchnet.punchnetservice.DISCONNECT"
}
override fun close() {
vpnDescriptor?.close()
}
override suspend fun recv(): ByteArray {
val result = withContext(Dispatchers.IO) {
val result = ByteArray(1500)
@ -135,18 +142,18 @@ class PunchnetService : VpnService() , IfaceTun {
}
Toast.makeText(this, "stop vpn called", Toast.LENGTH_LONG).show()
stopForeground(STOP_FOREGROUND_REMOVE)
input?.close()
output?.close()
vpnDescriptor?.close()
vpnDescriptor = null
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
isRunning.set(false)
}
}
private fun connect(startArg: PunchnetServiceArgument?) {
synchronized(serviceLock) {
if (isRunning.get()) {
return
@ -183,13 +190,13 @@ class PunchnetService : VpnService() , IfaceTun {
name = "tau",
)
scope.launch {
run_sdlan(scope, iface, argument, startArg)
}
val notification = createNotification()
startForeground(1, notification)
scope.launch {
run_sdlan(scope, start_stop_channel, iface, argument, startArg)
}
isRunning.set(true)
}
}
@ -199,12 +206,13 @@ class PunchnetService : VpnService() , IfaceTun {
return if (intent?.action == ACTION_DISCONNECT) {
scope.cancel()
disconnect()
START_STICKY
} else {
scope = CoroutineScope(Dispatchers.IO)
arpTable = ARPTable(scope)
disconnect()
START_NOT_STICKY
} else {
val argument = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent?.getParcelableExtra("argument", PunchnetServiceArgument::class.java)
} else {
@ -238,7 +246,9 @@ class PunchnetService : VpnService() , IfaceTun {
// scope.cancel()
// disconnect()
scope.cancel()
stopForeground(STOP_FOREGROUND_REMOVE)
disconnect()
Log.e(TAG, "onDestroy is called")
// stopForeground(STOP_FOREGROUND_REMOVE)
super.onDestroy()
}
}

View File

@ -7,6 +7,7 @@ import com.jihe.punchnet.protobuf.PunchProto.SDLStunProbe
import com.jihe.punchnet.protobuf.PunchProto.SDLStunProbeReply
import com.jihe.punchnet.protobuf.PunchProto.SDLStunRequest
import com.jihe.punchnet.sdlan.config.SDLanMulticastConfig
import com.jihe.punchnet.sdlan.logs.TerminalLogger
import com.jihe.punchnet.sdlan.utils.AES
import com.jihe.punchnet.sdlan.utils.RSA
import com.jihe.punchnet.sdlan.utils.UniqueNodeID
@ -312,8 +313,12 @@ class Node private constructor (
}
suspend fun _sendDataToSocket(msg: ByteArray) {
if (aes.isAuthorized()) {
TerminalLogger.debugf{"authorized, ping to sn"}
toSocket.send(msg)
} else {
TerminalLogger.debugf{"unauthorized, not ping to sn"}
}
}
}

View File

@ -30,6 +30,7 @@ interface Iface {
suspend fun send(content: ByteArray)
suspend fun reload_config(config: DeviceConfig)
fun close() {}
suspend fun handleDataFromNet(node: Node, data: ByteArray)
suspend fun handleDataFromDevice(node: Node, data: ByteArray)
}
@ -227,6 +228,9 @@ class IfaceMock: IfaceTun {
var config: DeviceConfig = DeviceConfig(0)
override fun close() {
}
override suspend fun recv(): ByteArray {
val result = withContext(Dispatchers.IO) {
val size = input.readInt()

View File

@ -26,6 +26,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.withContext
@ -47,7 +48,6 @@ suspend fun onMessage(scope: CoroutineScope, data: SDLanTCP) {
TerminalLogger.debugf {"message received"}
when(data.packetType) {
PacketType.RegisterSuperACK -> {
println("11")
val ack = SDLRegisterSuperAck.parseFrom(data.currentPacket)
// TerminalLogger.debugf { "got register super ack: $ack" }
println("ack is ${ack}")
@ -65,7 +65,9 @@ suspend fun onMessage(scope: CoroutineScope, data: SDLanTCP) {
node.deviceConfig.ip.netAddr = ack.devAddr.netAddr
node.deviceConfig.ip.netBitLen = ack.devAddr.netBitLen.toByte()
println("reloading config: node.iface = ${node.iface}")
node.iface?.reload_config(node.deviceConfig)
println("reloading config ok: node.iface = ${node.iface}")
node.networkID.set(ack.devAddr.networkId)
// println("got aes key: ${aeskey.toList()}, length is ${aeskey.size}")
@ -83,7 +85,6 @@ suspend fun onMessage(scope: CoroutineScope, data: SDLanTCP) {
*/
}
PacketType.RegisterSuperNAK -> {
println("21")
val nak = SDLRegisterSuperNak.parseFrom(data.currentPacket)
TerminalLogger.debugf { "got register super nak: $nak" }
val nakcode = NakMsgCode.fromByte(nak.errorCode.toByte())
@ -133,7 +134,7 @@ suspend fun onMessage(scope: CoroutineScope, data: SDLanTCP) {
}
suspend fun run_sdlan(scope: CoroutineScope, iface: Iface, argument: Arguments, routeinfo: PunchnetServiceArgument?) {
suspend fun run_sdlan(scope: CoroutineScope, start_stop_channel: Channel<StartStopChanInfo>, iface: Iface, argument: Arguments, routeinfo: PunchnetServiceArgument?) {
UniqueNodeID.setBaseDir(argument.baseDir)
val edgeUUID = UniqueNodeID.getUUID()
val config = parseConfig(edgeUUID, argument)
@ -146,7 +147,7 @@ suspend fun run_sdlan(scope: CoroutineScope, iface: Iface, argument: Arguments,
val toSocket = Channel<ByteArray>(100)
val start_stop_channel = Channel<StartStopChanInfo>(100)
// val start_stop_channel = Channel<StartStopChanInfo>(100)
initEdge(scope, iface, argument.token, config, toSocket, start_stop_channel)
val tcp = argument.tcp.split(":")
@ -158,10 +159,10 @@ suspend fun run_sdlan(scope: CoroutineScope, iface: Iface, argument: Arguments,
val before = ubyteArrayOf(126u,162u,25u,63u,148u,147u,198u,41u,69u,165u,149u,101u,153u,82u,190u,21u,48u,120u,26u,64u,142u,103u,159u,60u,47u,129u,176u,17u,232u,210u,36u,56u)
val encrypted = node.rsa.encrypt(before.toByteArray(), use_private_key = false)
println("encrypted: ${encrypted.contentToString()}")
// println("encrypted: ${encrypted.contentToString()}")
val origin = node.rsa.decrypt(encrypted, use_pub_key = false)
TerminalLogger.debugf { "got encrypted ${encrypted.size}"}
TerminalLogger.debugf { "got origin ${origin.contentToString()}"}
// TerminalLogger.debugf { "got encrypted ${encrypted.size}"}
// TerminalLogger.debugf { "got origin ${origin.contentToString()}"}
TerminalLogger.debugf { "self mac: ${macToString(node.mac)}"}
@ -199,24 +200,34 @@ suspend fun run_sdlan(scope: CoroutineScope, iface: Iface, argument: Arguments,
*/
scope.launch {
while(true) {
val data = node.iface?.recv()
Log.d("SDLAN", "async receive data from iface: ${data?.size} bytes")
if (data == null) {
//delay(1000)
println("got data is null")
continue
try {
while(true) {
if (node.iface == null) {
delay(1000)
continue
}
val data = node.iface?.recv()
Log.d("SDLAN", "async receive data from iface: ${data?.size} bytes")
if (data == null) {
//delay(1000)
delay(1000)
// println("got data is null")
continue
}
if (data.isEmpty()) {
delay(1000)
// println("got data size 0")
// delay(1000)
continue
}
Log.d("SDLAN", "handle data form device starts")
node.iface?.handleDataFromDevice(node, data)
Log.d("SDLAN", "handle data form device stops")
}
if (data.isEmpty()) {
println("got data size 0")
// delay(1000)
continue
}
Log.d("SDLAN", "handle data form device starts")
node.iface?.handleDataFromDevice(node, data)
Log.d("SDLAN", "handle data form device stops")
} catch (e: Exception) {
println("iface read is cancelled")
node.iface?.close()
}
}
/*
CoroutineScope((Dispatchers.IO)).async {
@ -242,20 +253,24 @@ suspend fun run_sdlan(scope: CoroutineScope, iface: Iface, argument: Arguments,
// CoroutineScope(Dispatchers.IO).async {
scope.launch {
initTCPConn(
scope,
tcp[0], tcp[1].toInt(),
start_stop_channel,
AtomicLong(now),
AtomicBoolean(false),
toSocket as ReceiveChannel<ByteArray>,
onConnected,
::onMessage,
suspend {
node.aes.setSecret(null)
},
null,
)
try {
initTCPConn(
scope,
tcp[0], tcp[1].toInt(),
start_stop_channel,
AtomicLong(now),
AtomicBoolean(false),
toSocket as ReceiveChannel<ByteArray>,
onConnected,
::onMessage,
suspend {
node.aes.setSecret(null)
},
null,
)
} finally {
println("initTCPConn is cancelled")
}
}
@ -354,6 +369,7 @@ suspend fun handleAPacket(scope: CoroutineScope, node: Node, from: SocketAddress
return
}
PacketType.Register -> {
TerminalLogger.debugf { "got REGISTER" }
if (from is InetSocketAddress) {
val sock = SDLanSock(IPFamily.IPV4, from.port, from.address.address)
handlePacketRegister(node, data, sock)
@ -419,17 +435,20 @@ suspend fun initTCPConn(
onDisconnected: suspend ()->Unit,
connectingChan: SendChannel<ConnectingState>?
) {
var started: Boolean = false
val started = AtomicBoolean(false)
// var started: Boolean = false
var startPktID: Int? = null
while(true) {
connectingChan?.send(ConnectingState.NotConnected)
if (!started) {
if (!started.get()) {
while(true) {
println("waiting for start_stop")
val startStopInfo = start_stop.receive()
if (startStopInfo.flag == StartStopFlag.IsStart) {
started = true
started.set(true)
// started = true
startPktID = startStopInfo.packetID
break
}
@ -518,11 +537,11 @@ suspend fun initTCPConn(
try {
val v = start_stop.receive()
if (v.flag == StartStopFlag.IsStop) {
started = false
started.set(false)
break
}
} catch(e: Exception) {
started = false
started.set(false)
break
}
@ -549,10 +568,15 @@ suspend fun initTCPConn(
}
}
println("m1")
job_read_packet.cancelAndJoin()
println("m2")
job_write_to_packet.cancelAndJoin()
println("m3")
job_check_pong.cancelAndJoin()
println("m4")
job_check_stop.cancelAndJoin()
println("m5")
delay(1000)
}

View File

@ -43,21 +43,13 @@ class AES private constructor () {
if (!isAuthorized()) {
return null
}
println(11.0)
val cipher = Cipher.getInstance(AESConfig.CIPHER_ALGORITHM)
println(11.1)
val keyspec = SecretKeySpec(_secret, AESConfig.KEY_SPEC)
println(11.2)
println(11.3)
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, IvParameterSpec(_iv))
println(10.0)
val output = ByteBuffer.allocate(cipher.getOutputSize(content.remaining()))
println(10.1)
cipher.doFinal(content, output)
println(10.2)
output.flip()
println(10.3)
return output
} catch (e: Exception) {
println("failed to encrypt: ${e.toString()}")