package com.jihe.punchnet import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.Intent import android.net.VpnService import android.os.Build import android.os.Environment import android.os.ParcelFileDescriptor import android.util.Log import android.widget.Toast import androidx.core.app.NotificationCompat import androidx.lifecycle.ViewModelProvider import com.jihe.punchnet.data.RouteItem import com.jihe.punchnet.data.RouteViewModel import com.jihe.punchnet.sdlan.config.Arguments import com.jihe.punchnet.sdlan.config.toIPV4String import com.jihe.punchnet.sdlan.logs.TerminalLogger import com.jihe.punchnet.sdlan.network.ARPTable import com.jihe.punchnet.sdlan.network.ARPWaitList 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.cidrToRouteDetail import com.jihe.punchnet.sdlan.network.ipInt2ByteArray import com.jihe.punchnet.sdlan.network.maskIPToDigit import com.jihe.punchnet.sdlan.network.run_sdlan import com.jihe.punchnet.sdlan.utils.ipToString import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.FileInputStream import java.io.FileOutputStream class PunchnetService : VpnService() , IfaceTun { private val TAG = "PunchnetService" private var scope = CoroutineScope(Dispatchers.IO) private val routes: MutableList = mutableListOf() private var vpnDescriptor: ParcelFileDescriptor? = null var input: FileInputStream? = null var output: FileOutputStream? = null override var arpTable = ARPTable(scope) override val arpWaitList = ARPWaitList() var config: DeviceConfig = DeviceConfig(1400) companion object { const val ACTION_CONNECT = "com.jihe.punchnet.punchnetservice.CONNECT" const val ACTION_DISCONNECT = "com.jihe.punchnet.punchnetservice.DISCONNECT" } override suspend fun recv(): ByteArray { val result = withContext(Dispatchers.IO) { val result = ByteArray(1500) try { var size = input?.read(result) if (size == null) { println("xxx failed to read") size = 0 } else { println("xxx got $size bytes") } // val size = input?.read(result)?:0 // Log.d(TAG, "RECEIVED $size bytes") result.copyOf(size) // result.slice(0..= Build.VERSION_CODES.TIRAMISU) { intent?.getParcelableExtra("argument", PunchnetServiceArgument::class.java) } else { intent?.getParcelableExtra("argument") } println("argument = ${argument}") connect(argument) START_STICKY } // return super.onStartCommand(intent, flags, startId) } private fun createNotification(): Notification { val channelId = "punchnet_channel" val channel = NotificationChannel ( channelId, "punchnet", NotificationManager.IMPORTANCE_DEFAULT ) val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager manager.createNotificationChannel(channel) return NotificationCompat.Builder(this, channelId) .setContentTitle("Punchnet Service") .setContentText("Punchnet is running") .setSmallIcon(R.drawable.ic_vpn) .build() } override fun onDestroy() { // scope.cancel() // disconnect() scope.cancel() stopForeground(STOP_FOREGROUND_REMOVE) super.onDestroy() } }