mirror of
https://github.com/openp2p-cn/openp2p.git
synced 2025-12-24 12:57:52 +08:00
install bug and new log api
This commit is contained in:
@@ -4,7 +4,6 @@ import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import java.io.IOException
|
||||
import android.net.VpnService
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
@@ -22,6 +21,13 @@ import java.io.FileOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import kotlinx.coroutines.*
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.net.InetAddress
|
||||
import java.net.NetworkInterface
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import java.nio.channels.FileChannel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
data class Node(val name: String, val ip: String, val resource: String? = null)
|
||||
|
||||
@@ -32,9 +38,10 @@ data class Network(
|
||||
val gateway: String,
|
||||
val Nodes: List<Node>
|
||||
)
|
||||
|
||||
class OpenP2PService : VpnService() {
|
||||
companion object {
|
||||
private val LOG_TAG = OpenP2PService::class.simpleName
|
||||
private val LOG_TAG = "OpenP2PService"
|
||||
}
|
||||
|
||||
inner class LocalBinder : Binder() {
|
||||
@@ -44,12 +51,17 @@ class OpenP2PService : VpnService() {
|
||||
private val binder = LocalBinder()
|
||||
private lateinit var network: openp2p.P2PNetwork
|
||||
private lateinit var mToken: String
|
||||
private var running:Boolean =true
|
||||
private var sdwanRunning:Boolean =false
|
||||
private var running: Boolean = true
|
||||
private var sdwanRunning: Boolean = false
|
||||
private var vpnInterface: ParcelFileDescriptor? = null
|
||||
private var sdwanJob: Job? = null
|
||||
private var sdwanJob: Job? = null
|
||||
private val packetQueue = Channel<ByteBuffer>(capacity = 1024)
|
||||
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
override fun onCreate() {
|
||||
Log.i(LOG_TAG, "onCreate - Thread ID = " + Thread.currentThread().id)
|
||||
val logDir = File(getExternalFilesDir(null), "log")
|
||||
Logger.init(logDir)
|
||||
Logger.i(LOG_TAG, "onCreate - Thread ID = " + Thread.currentThread().id)
|
||||
var channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createNotificationChannel("kim.hsl", "ForegroundService")
|
||||
} else {
|
||||
@@ -64,7 +76,7 @@ class OpenP2PService : VpnService() {
|
||||
|
||||
val notification = channelId?.let {
|
||||
NotificationCompat.Builder(this, it)
|
||||
// .setSmallIcon(R.mipmap.app_icon)
|
||||
// .setSmallIcon(R.mipmap.app_icon)
|
||||
.setContentTitle("My Awesome App")
|
||||
.setContentText("Doing some work...")
|
||||
.setContentIntent(pendingIntent).build()
|
||||
@@ -76,7 +88,7 @@ class OpenP2PService : VpnService() {
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.i(
|
||||
Logger.i(
|
||||
LOG_TAG,
|
||||
"onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().id
|
||||
)
|
||||
@@ -86,20 +98,20 @@ class OpenP2PService : VpnService() {
|
||||
|
||||
override fun onBind(p0: Intent?): IBinder? {
|
||||
val token = p0?.getStringExtra("token")
|
||||
Log.i(LOG_TAG, "onBind token=$token")
|
||||
Logger.i(LOG_TAG, "onBind token=$token")
|
||||
startOpenP2P(token)
|
||||
return binder
|
||||
}
|
||||
|
||||
private fun startOpenP2P(token : String?): Boolean {
|
||||
private fun startOpenP2P(token: String?): Boolean {
|
||||
if (sdwanRunning) {
|
||||
return true
|
||||
}
|
||||
|
||||
Log.i(LOG_TAG, "startOpenP2P - Thread ID = " + Thread.currentThread().id + token)
|
||||
Logger.i(LOG_TAG, "startOpenP2P - Thread ID = " + Thread.currentThread().id + token)
|
||||
val oldToken = Openp2p.getToken(getExternalFilesDir(null).toString())
|
||||
Log.i(LOG_TAG, "startOpenP2P oldtoken=$oldToken newtoken=$token")
|
||||
if (oldToken=="0" && token==null){
|
||||
Logger.i(LOG_TAG, "startOpenP2P oldtoken=$oldToken newtoken=$token")
|
||||
if (oldToken == "0" && token == null) {
|
||||
return false
|
||||
}
|
||||
sdwanRunning = true
|
||||
@@ -112,7 +124,7 @@ class OpenP2PService : VpnService() {
|
||||
1
|
||||
) // /storage/emulated/0/Android/data/cn.openp2p/files/
|
||||
val isConnect = network.connect(30000) // ms
|
||||
Log.i(LOG_TAG, "login result: " + isConnect.toString());
|
||||
Logger.i(LOG_TAG, "login result: " + isConnect.toString());
|
||||
do {
|
||||
Thread.sleep(1000)
|
||||
} while (network.connect(30000) && running)
|
||||
@@ -123,152 +135,257 @@ class OpenP2PService : VpnService() {
|
||||
|
||||
private fun refreshSDWAN() {
|
||||
GlobalScope.launch {
|
||||
Log.i(OpenP2PService.LOG_TAG, "refreshSDWAN start");
|
||||
Logger.i(OpenP2PService.LOG_TAG, "refreshSDWAN start");
|
||||
while (true) {
|
||||
Log.i(OpenP2PService.LOG_TAG, "waiting new sdwan config");
|
||||
val buf = ByteArray(4096)
|
||||
Logger.i(OpenP2PService.LOG_TAG, "waiting new sdwan config");
|
||||
val buf = ByteArray(32 * 1024)
|
||||
val buffLen = Openp2p.getAndroidSDWANConfig(buf)
|
||||
Log.i(OpenP2PService.LOG_TAG, "closing running sdwan instance");
|
||||
Logger.i(OpenP2PService.LOG_TAG, "closing running sdwan instance");
|
||||
sdwanRunning = false
|
||||
vpnInterface?.close()
|
||||
vpnInterface = null
|
||||
Thread.sleep(10000)
|
||||
runSDWAN(buf.copyOfRange(0,buffLen.toInt() ))
|
||||
sdwanJob?.join()
|
||||
sdwanJob = serviceScope.launch(context = Dispatchers.IO) {
|
||||
runSDWAN(buf.copyOfRange(0, buffLen.toInt()))
|
||||
}
|
||||
}
|
||||
Log.i(OpenP2PService.LOG_TAG, "refreshSDWAN end");
|
||||
Logger.i(OpenP2PService.LOG_TAG, "refreshSDWAN end");
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun readTunLoop() {
|
||||
val inputStream = FileInputStream(vpnInterface?.fileDescriptor).channel
|
||||
if (inputStream==null){
|
||||
Log.i(OpenP2PService.LOG_TAG, "open FileInputStream error: ");
|
||||
if (inputStream == null) {
|
||||
Logger.i(OpenP2PService.LOG_TAG, "open FileInputStream error: ");
|
||||
return
|
||||
}
|
||||
Log.d(LOG_TAG, "read tun loop start")
|
||||
Logger.i(LOG_TAG, "read tun loop start")
|
||||
val buffer = ByteBuffer.allocate(4096)
|
||||
val byteArrayRead = ByteArray(4096)
|
||||
while (sdwanRunning) {
|
||||
buffer.clear()
|
||||
val readBytes = inputStream.read(buffer)
|
||||
if (readBytes <= 0) {
|
||||
// Log.i(OpenP2PService.LOG_TAG, "inputStream.read error: ")
|
||||
delay(1)
|
||||
continue
|
||||
withContext(Dispatchers.IO) {
|
||||
val readBytes = inputStream.read(buffer)
|
||||
if (readBytes > 0) {
|
||||
buffer.flip()
|
||||
buffer.get(byteArrayRead, 0, readBytes)
|
||||
// Logger.i(OpenP2PService.LOG_TAG, String.format("Openp2p.androidRead: %d", readBytes))
|
||||
Openp2p.androidRead(byteArrayRead, readBytes.toLong())
|
||||
// Logger.i(OpenP2PService.LOG_TAG, "inputStream.read error: ")
|
||||
} else {
|
||||
delay(50)
|
||||
}
|
||||
}
|
||||
buffer.flip()
|
||||
buffer.get(byteArrayRead,0,readBytes)
|
||||
Log.i(OpenP2PService.LOG_TAG, String.format("Openp2p.androidRead: %d", readBytes))
|
||||
Openp2p.androidRead(byteArrayRead, readBytes.toLong())
|
||||
|
||||
}
|
||||
Log.d(LOG_TAG, "read tun loop end")
|
||||
Logger.i(LOG_TAG, "read tun loop end")
|
||||
}
|
||||
|
||||
private fun runSDWAN(buf:ByteArray) {
|
||||
sdwanRunning=true
|
||||
sdwanJob=GlobalScope.launch(context = Dispatchers.IO) {
|
||||
Log.i(OpenP2PService.LOG_TAG, "runSDWAN start:${buf.decodeToString()}");
|
||||
try{
|
||||
var builder = Builder()
|
||||
val jsonObject = JSONObject(buf.decodeToString())
|
||||
val id = jsonObject.getLong("id")
|
||||
val name = jsonObject.getString("name")
|
||||
val gateway = jsonObject.getString("gateway")
|
||||
val nodesArray = jsonObject.getJSONArray("Nodes")
|
||||
|
||||
val nodesList = mutableListOf<JSONObject>()
|
||||
for (i in 0 until nodesArray.length()) {
|
||||
nodesList.add(nodesArray.getJSONObject(i))
|
||||
}
|
||||
private suspend fun runSDWAN(buf: ByteArray) {
|
||||
// val localIps = listOf(
|
||||
// "fe80::14b6:a0ff:fe3e:64de" to 64,
|
||||
// "192.168.100.184" to 24,
|
||||
// "10.93.158.91" to 32,
|
||||
// "192.168.3.66" to 24
|
||||
// )
|
||||
//
|
||||
// // 测试用例
|
||||
// val testCases = listOf(
|
||||
// "192.168.3.11" to true,
|
||||
// "192.168.100.1" to true,
|
||||
// "192.168.101.1" to false,
|
||||
// "10.93.158.91" to true,
|
||||
// "10.93.158.90" to false,
|
||||
// "fe80::14b6:a0ff:fe3e:64de" to true,
|
||||
// "fe80::14b6:a0ff:fe3e:64dd" to true // 在同一子网
|
||||
// )
|
||||
//
|
||||
// for ((ip, expected) in testCases) {
|
||||
// val result = isSameSubnet(ip, localIps)
|
||||
// println("Testing IP: $ip, Expected: $expected, Result: $result")
|
||||
// }
|
||||
sdwanRunning = true
|
||||
|
||||
val myNodeName = Openp2p.getAndroidNodeName()
|
||||
Log.i(OpenP2PService.LOG_TAG, "getAndroidNodeName:${myNodeName}");
|
||||
val nodeList = nodesList.map {
|
||||
val nodeName = it.getString("name")
|
||||
val nodeIp = it.getString("ip")
|
||||
if (nodeName==myNodeName){
|
||||
Logger.i(OpenP2PService.LOG_TAG, "runSDWAN start:${buf.decodeToString()}");
|
||||
try {
|
||||
var builder = Builder()
|
||||
val jsonObject = JSONObject(buf.decodeToString())
|
||||
// debug sdwan info
|
||||
// val jsonObject = JSONObject("""{"id":2817104318517097000,"name":"network1","gateway":"10.2.3.254/24","mode":"central","centralNode":"nanjin-192-168-0-82","enable":1,"tunnelNum":3,"mtu":1420,"Nodes":[{"name":"192-168-24-15","ip":"10.2.3.5"},{"name":"Alpine Linux-172.16","ip":"10.2.3.14","resource":"172.16.0.0/24"},{"name":"ctdeMacBook-Pro.local","ip":"10.2.3.22"},{"name":"dengjiandeMBP.sh.chaitin.net","ip":"10.2.3.32"},{"name":"DESKTOP-WIN11-ARM-self","ip":"10.2.3.19"},{"name":"eastdeMBP.sh.chaitin.net","ip":"10.2.3.3"},{"name":"FN-NAS-HP","ip":"10.2.3.1","resource":"192.168.100.0/24"},{"name":"huangruideMBP.sh.chaitin.net","ip":"10.2.3.30"},{"name":"iStoreOS-virtual-machine","ip":"10.2.3.12"},{"name":"k30s-redmi-10.2.33","ip":"10.2.3.27"},{"name":"lincheng-MacBook-Pro-3.sh.chaitin.net","ip":"10.2.3.15"},{"name":"localhost-mi-13","ip":"10.2.3.8"},{"name":"localhost-华为matepad11","ip":"10.2.3.13"},{"name":"luzhanwendeMacBook-Pro.local","ip":"10.2.3.17"},{"name":"Mi-pad2-local","ip":"10.2.3.9"},{"name":"nanjin-192-168-0-82","ip":"10.2.3.34"},{"name":"R7000P-2021","ip":"10.2.3.7"},{"name":"tanxiaolongsMBP.sh.chaitin.net","ip":"10.2.3.20"},{"name":"TUF-AX3000_V2-3804","ip":"10.2.3.25"},{"name":"WIN-CYZ-10.2.3.16","ip":"10.2.3.16"},{"name":"WODOUYAO","ip":"10.2.3.4"},{"name":"Zstrack01","ip":"10.2.3.51","resource":"192.168.24.0/22,192.168.20.0/24"},{"name":"小米14-localhost","ip":"10.2.3.23"}]}""")
|
||||
val id = jsonObject.getLong("id")
|
||||
val mtu = jsonObject.getInt("mtu")
|
||||
val name = jsonObject.getString("name")
|
||||
val gateway = jsonObject.getString("gateway")
|
||||
val nodesArray = jsonObject.getJSONArray("Nodes")
|
||||
|
||||
val nodesList = mutableListOf<JSONObject>()
|
||||
for (i in 0 until nodesArray.length()) {
|
||||
nodesList.add(nodesArray.getJSONObject(i))
|
||||
}
|
||||
|
||||
val myNodeName = Openp2p.getAndroidNodeName()
|
||||
// 使用本地 IP 和子网判断是否需要添加路由
|
||||
val localIps = getLocalIpAndSubnet()
|
||||
Logger.i(OpenP2PService.LOG_TAG, "getAndroidNodeName:${myNodeName}");
|
||||
val nodeList = nodesList.map {
|
||||
val nodeName = it.getString("name")
|
||||
val nodeIp = it.getString("ip")
|
||||
if (nodeName == myNodeName) {
|
||||
try {
|
||||
Logger.i(LOG_TAG, "Attempting to add address: $nodeIp/24")
|
||||
builder.addAddress(nodeIp, 24)
|
||||
Logger.i(LOG_TAG, "Successfully added address")
|
||||
} catch (e: Exception) {
|
||||
Logger.e(LOG_TAG, "Failed to add address $nodeIp: ${e.message}")
|
||||
throw e // or handle gracefully
|
||||
}
|
||||
val nodeResource = if (it.has("resource")) it.getString("resource") else null
|
||||
val parts = nodeResource?.split("/")
|
||||
if (parts?.size == 2) {
|
||||
val ipAddress = parts[0]
|
||||
val subnetMask = parts[1]
|
||||
builder.addRoute(ipAddress, subnetMask.toInt())
|
||||
Log.i(OpenP2PService.LOG_TAG, "sdwan addRoute:${ipAddress},${subnetMask.toInt()}");
|
||||
}
|
||||
val nodeResource = it.optString("resource", null)
|
||||
if (!nodeResource.isNullOrEmpty()) {
|
||||
// 可能是多个网段,用逗号分隔
|
||||
val resourceList = nodeResource.split(",")
|
||||
for (resource in resourceList) {
|
||||
val parts = resource.split("/")
|
||||
if (parts.size == 2) {
|
||||
val ipAddress = parts[0].trim()
|
||||
val subnetMask = parts[1].trim()
|
||||
// 判断是否属于本机网段
|
||||
if (!isSameSubnet(ipAddress, localIps)) {
|
||||
builder.addRoute(ipAddress, subnetMask.toInt())
|
||||
Logger.i(
|
||||
OpenP2PService.LOG_TAG,
|
||||
"sdwan addRoute:${ipAddress},${subnetMask}"
|
||||
)
|
||||
} else {
|
||||
Logger.i(
|
||||
OpenP2PService.LOG_TAG,
|
||||
"Skipped adding route for ${ipAddress}, already in local subnet"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Logger.w(OpenP2PService.LOG_TAG, "Invalid resource format: $resource")
|
||||
}
|
||||
}
|
||||
Node(nodeName, nodeIp, nodeResource)
|
||||
}
|
||||
|
||||
val network = Network(id, name, gateway, nodeList)
|
||||
println(network)
|
||||
Log.i(OpenP2PService.LOG_TAG, "onBind");
|
||||
builder.addDnsServer("223.5.5.5")
|
||||
builder.addDnsServer("2400:3200::1") // alicloud dns v6 & v4
|
||||
builder.addRoute("10.2.3.0", 24)
|
||||
// builder.addRoute("0.0.0.0", 0);
|
||||
builder.setSession(LOG_TAG!!)
|
||||
builder.setMtu(1420)
|
||||
vpnInterface = builder.establish()
|
||||
if (vpnInterface==null){
|
||||
Log.e(OpenP2PService.LOG_TAG, "start vpnservice error: ");
|
||||
}
|
||||
val outputStream = FileOutputStream(vpnInterface?.fileDescriptor).channel
|
||||
if (outputStream==null){
|
||||
Log.e(OpenP2PService.LOG_TAG, "open FileOutputStream error: ");
|
||||
return@launch
|
||||
}
|
||||
|
||||
val byteArrayWrite = ByteArray(4096)
|
||||
launch {
|
||||
readTunLoop()
|
||||
}
|
||||
|
||||
Log.d(LOG_TAG, "write tun loop start")
|
||||
while (sdwanRunning) {
|
||||
val len = Openp2p.androidWrite(byteArrayWrite)
|
||||
Log.i(OpenP2PService.LOG_TAG, String.format("Openp2p.androidWrite: %d",len));
|
||||
val writeBytes = outputStream?.write(ByteBuffer.wrap(byteArrayWrite))
|
||||
if (writeBytes != null && writeBytes <= 0) {
|
||||
Log.i(OpenP2PService.LOG_TAG, "outputStream?.write error: ");
|
||||
continue
|
||||
}
|
||||
}
|
||||
outputStream.close()
|
||||
// 关闭 VPN 接口
|
||||
vpnInterface?.close()
|
||||
// 置空变量以释放资源
|
||||
vpnInterface = null
|
||||
Log.d(LOG_TAG, "write tun loop end")
|
||||
}catch (e: Exception) {
|
||||
// 捕获异常并记录
|
||||
Log.e("VPN Connection", "发生异常: ${e.message}")
|
||||
Node(nodeName, nodeIp, nodeResource)
|
||||
}
|
||||
Log.i(OpenP2PService.LOG_TAG, "runSDWAN end");
|
||||
|
||||
val network = Network(id, name, gateway, nodeList)
|
||||
println(network)
|
||||
Logger.i(OpenP2PService.LOG_TAG, "onBind");
|
||||
builder.addDnsServer("119.29.29.29")
|
||||
builder.addDnsServer("2400:3200::1") // alicloud dns v6 & v4
|
||||
// builder.addRoute("10.2.3.0", 24)
|
||||
// builder.addRoute("0.0.0.0", 0);
|
||||
val gatewayStr = jsonObject.optString("gateway", "")
|
||||
val subNet = getNetworkAddress(gatewayStr)
|
||||
if (subNet != null) {
|
||||
val (netIp, prefix) = subNet
|
||||
builder.addRoute(netIp, prefix)
|
||||
Logger.i(OpenP2PService.LOG_TAG, "Added route from gateway: $netIp/$prefix")
|
||||
} else {
|
||||
Logger.w(OpenP2PService.LOG_TAG, "Invalid gateway format: $gatewayStr")
|
||||
}
|
||||
|
||||
builder.setSession(LOG_TAG!!)
|
||||
builder.setMtu(mtu)
|
||||
vpnInterface = builder.establish()
|
||||
if (vpnInterface == null) {
|
||||
Log.e(OpenP2PService.LOG_TAG, "start vpnservice error: ");
|
||||
}
|
||||
|
||||
val byteArrayWrite = ByteArray(4096)
|
||||
serviceScope.launch(Dispatchers.IO) {
|
||||
readTunLoop() // 文件读操作,适合 Dispatchers.IO
|
||||
}
|
||||
|
||||
val outputStream = FileOutputStream(vpnInterface?.fileDescriptor).channel
|
||||
if (outputStream == null) {
|
||||
Log.e(OpenP2PService.LOG_TAG, "open FileOutputStream error: ");
|
||||
return
|
||||
}
|
||||
Logger.i(LOG_TAG, "write tun loop start")
|
||||
while (sdwanRunning) {
|
||||
val len = Openp2p.androidWrite(byteArrayWrite, 3000)
|
||||
if (len > mtu || len.toInt() == 0) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
val writeBytes =
|
||||
outputStream?.write(ByteBuffer.wrap(byteArrayWrite, 0, len.toInt()))
|
||||
if (writeBytes != null && writeBytes <= 0) {
|
||||
Logger.e(LOG_TAG, "outputStream.write failed: $writeBytes")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.e(LOG_TAG, "outputStream.write exception: ${e.message}")
|
||||
e.printStackTrace()
|
||||
continue
|
||||
}
|
||||
}
|
||||
outputStream.close()
|
||||
vpnInterface?.close()
|
||||
vpnInterface = null
|
||||
Logger.i(LOG_TAG, "write tun loop end")
|
||||
} catch (e: Exception) {
|
||||
Logger.i("VPN Connection", "发生异常: ${e.message}")
|
||||
}
|
||||
|
||||
Logger.i(OpenP2PService.LOG_TAG, "runSDWAN end");
|
||||
}
|
||||
/**
|
||||
* 将 "10.2.3.254/16" 这样的 CIDR 转成正确对齐的网络地址,如 "10.2.0.0/16"
|
||||
*/
|
||||
fun getNetworkAddress(cidr: String): Pair<String, Int>? {
|
||||
val parts = cidr.trim().split("/")
|
||||
if (parts.size != 2) return null
|
||||
|
||||
val ip = parts[0]
|
||||
val prefix = parts[1].toIntOrNull() ?: return null
|
||||
if (prefix !in 0..32) return null
|
||||
|
||||
val octets = ip.split(".").map { it.toInt() }
|
||||
if (octets.size != 4) return null
|
||||
|
||||
// 转成整数
|
||||
val ipInt = (octets[0] shl 24) or (octets[1] shl 16) or (octets[2] shl 8) or octets[3]
|
||||
|
||||
// 生成掩码并计算网络地址
|
||||
val mask = if (prefix == 0) 0 else (-1 shl (32 - prefix))
|
||||
val networkInt = ipInt and mask
|
||||
|
||||
// 转回点分十进制
|
||||
val networkIp = listOf(
|
||||
(networkInt shr 24) and 0xFF,
|
||||
(networkInt shr 16) and 0xFF,
|
||||
(networkInt shr 8) and 0xFF,
|
||||
networkInt and 0xFF
|
||||
).joinToString(".")
|
||||
|
||||
return networkIp to prefix
|
||||
}
|
||||
override fun onDestroy() {
|
||||
Log.i(LOG_TAG, "onDestroy - Thread ID = " + Thread.currentThread().id)
|
||||
super.onDestroy()
|
||||
Logger.i(LOG_TAG, "onDestroy - Canceling service scope")
|
||||
serviceScope.cancel() // 取消所有与服务相关的协程
|
||||
}
|
||||
|
||||
override fun onUnbind(intent: Intent?): Boolean {
|
||||
Log.i(LOG_TAG, "onUnbind - Thread ID = " + Thread.currentThread().id)
|
||||
Logger.i(LOG_TAG, "onUnbind - Thread ID = " + Thread.currentThread().id)
|
||||
stopSelf()
|
||||
return super.onUnbind(intent)
|
||||
}
|
||||
|
||||
fun isConnected(): Boolean {
|
||||
if (!::network.isInitialized) return false
|
||||
return network.connect(1000)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
running=false
|
||||
running = false
|
||||
stopSelf()
|
||||
Openp2p.stop()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createNotificationChannel(channelId: String, channelName: String): String? {
|
||||
val chan = NotificationChannel(
|
||||
@@ -281,4 +398,55 @@ class OpenP2PService : VpnService() {
|
||||
service.createNotificationChannel(chan)
|
||||
return channelId
|
||||
}
|
||||
}
|
||||
|
||||
// 获取本机所有IP地址和对应的子网信息
|
||||
fun getLocalIpAndSubnet(): List<Pair<String, Int>> {
|
||||
val localIps = mutableListOf<Pair<String, Int>>()
|
||||
val networkInterfaces = NetworkInterface.getNetworkInterfaces()
|
||||
// 手动添加测试数据
|
||||
//localIps.add(Pair("192.168.3.33", 24))
|
||||
while (networkInterfaces.hasMoreElements()) {
|
||||
val networkInterface = networkInterfaces.nextElement()
|
||||
if (networkInterface.isUp && !networkInterface.isLoopback) {
|
||||
val interfaceAddresses = networkInterface.interfaceAddresses
|
||||
for (interfaceAddress in interfaceAddresses) {
|
||||
val address = interfaceAddress.address
|
||||
val prefixLength = interfaceAddress.networkPrefixLength
|
||||
if (address is InetAddress) {
|
||||
localIps.add(Pair(address.hostAddress, prefixLength.toInt()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return localIps
|
||||
}
|
||||
|
||||
// 判断某个IP是否与本机某网段匹配
|
||||
fun isSameSubnet(ipAddress: String, localIps: List<Pair<String, Int>>): Boolean {
|
||||
val targetIp = InetAddress.getByName(ipAddress).address
|
||||
for ((localIp, prefixLength) in localIps) {
|
||||
val localIpBytes = InetAddress.getByName(localIp).address
|
||||
val mask = createSubnetMask(prefixLength, localIpBytes.size) // 动态生成掩码
|
||||
|
||||
// 比较目标 IP 和本地 IP 的网络部分
|
||||
if (targetIp.indices.all { i ->
|
||||
(targetIp[i].toInt() and mask[i].toInt()) == (localIpBytes[i].toInt() and mask[i].toInt())
|
||||
}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 根据前缀长度动态生成子网掩码
|
||||
fun createSubnetMask(prefixLength: Int, addressLength: Int): ByteArray {
|
||||
val mask = ByteArray(addressLength)
|
||||
for (i in 0 until prefixLength / 8) {
|
||||
mask[i] = 0xFF.toByte()
|
||||
}
|
||||
if (prefixLength % 8 != 0) {
|
||||
mask[prefixLength / 8] = (0xFF shl (8 - (prefixLength % 8))).toByte()
|
||||
}
|
||||
return mask
|
||||
}
|
||||
@@ -1,45 +1,91 @@
|
||||
package cn.openp2p
|
||||
import android.content.*
|
||||
import android.util.Log
|
||||
import java.text.SimpleDateFormat
|
||||
import java.io.BufferedWriter
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import java.io.IOException
|
||||
import android.net.VpnService
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import cn.openp2p.ui.login.LoginActivity
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import openp2p.Openp2p
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import kotlinx.coroutines.*
|
||||
import org.json.JSONObject
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
object Logger {
|
||||
private val logFile: File = File("app.log")
|
||||
private const val LOG_TAG = "OpenP2PLogger"
|
||||
private var logFile: File? = null
|
||||
private var bufferedWriter: BufferedWriter? = null
|
||||
|
||||
fun log(message: String) {
|
||||
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
|
||||
val logMessage = "$timestamp: $message\n"
|
||||
// 初始化日志文件
|
||||
fun init(logDir: File, logFileName: String = "app.log") {
|
||||
if (!logDir.exists()) logDir.mkdirs()
|
||||
logFile = File(logDir, logFileName)
|
||||
|
||||
try {
|
||||
val fileWriter = FileWriter(logFile, true)
|
||||
fileWriter.append(logMessage)
|
||||
fileWriter.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
bufferedWriter = BufferedWriter(FileWriter(logFile, true))
|
||||
} catch (e: IOException) {
|
||||
Log.e(LOG_TAG, "Failed to initialize BufferedWriter: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
// 写日志(线程安全)
|
||||
@Synchronized
|
||||
fun log(level: String, tag: String, message: String, throwable: Throwable? = null) {
|
||||
val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
|
||||
val logMessage = "$timestamp $level $tag: $message"
|
||||
|
||||
// 打印到 console
|
||||
when (level) {
|
||||
"ERROR" -> Log.e(tag, message, throwable)
|
||||
"WARN" -> Log.w(tag, message, throwable)
|
||||
"INFO" -> Log.i(tag, message)
|
||||
"DEBUG" -> Log.d(tag, message)
|
||||
"VERBOSE" -> Log.v(tag, message)
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
try {
|
||||
bufferedWriter?.apply {
|
||||
write(logMessage)
|
||||
newLine()
|
||||
flush()
|
||||
}
|
||||
throwable?.let {
|
||||
bufferedWriter?.apply {
|
||||
write(Log.getStackTraceString(it))
|
||||
newLine()
|
||||
flush()
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(LOG_TAG, "Failed to write log to file: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
fun close() {
|
||||
try {
|
||||
bufferedWriter?.close()
|
||||
} catch (e: IOException) {
|
||||
Log.e(LOG_TAG, "Failed to close BufferedWriter: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
// 简化方法
|
||||
fun e(tag: String, message: String, throwable: Throwable? = null) {
|
||||
log("ERROR", tag, message, throwable)
|
||||
}
|
||||
|
||||
fun w(tag: String, message: String, throwable: Throwable? = null) {
|
||||
log("WARN", tag, message, throwable)
|
||||
}
|
||||
|
||||
fun i(tag: String, message: String) {
|
||||
log("INFO", tag, message)
|
||||
}
|
||||
|
||||
fun d(tag: String, message: String) {
|
||||
log("DEBUG", tag, message)
|
||||
}
|
||||
|
||||
fun v(tag: String, message: String) {
|
||||
log("VERBOSE", tag, message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
op "openp2p/core"
|
||||
op2p "openp2p/core"
|
||||
)
|
||||
|
||||
func main() {
|
||||
op.Run()
|
||||
op2p.Run()
|
||||
}
|
||||
|
||||
@@ -30,4 +30,7 @@ var (
|
||||
ErrBuildTunnelBusy = errors.New("build tunnel busy")
|
||||
ErrMemAppTunnelNotFound = errors.New("memapp tunnel not found")
|
||||
ErrRemoteServiceUnable = errors.New("remote service unable")
|
||||
ErrAppWithoutTunnel = errors.New("p2papp has no available tunnel")
|
||||
ErrWriteWindowFull = errors.New("writeWindow full")
|
||||
ErrHeaderDataLen = errors.New("header datalen error")
|
||||
)
|
||||
|
||||
@@ -11,26 +11,14 @@ import (
|
||||
)
|
||||
|
||||
func install() {
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "install start")
|
||||
defer gLog.Println(LvINFO, "install end")
|
||||
// auto uninstall
|
||||
err := os.MkdirAll(defaultInstallPath, 0775)
|
||||
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
||||
return
|
||||
}
|
||||
err = os.Chdir(defaultInstallPath)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "Chdir error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
uninstall()
|
||||
// save config file
|
||||
gLog.i("openp2p start. version: %s", OpenP2PVersion)
|
||||
gLog.i("Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.i("install start")
|
||||
defer gLog.i("install end")
|
||||
parseParams("install", "")
|
||||
// auto uninstall
|
||||
uninstall(false)
|
||||
gLog.i("install path: %s", defaultInstallPath)
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
d := daemon{}
|
||||
// copy files
|
||||
@@ -38,37 +26,42 @@ func install() {
|
||||
binPath, _ := os.Executable()
|
||||
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.Open %s error:%s", os.Args[0], errFiles)
|
||||
gLog.e("os.Open %s error:%s", os.Args[0], errFiles)
|
||||
return
|
||||
}
|
||||
|
||||
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
|
||||
return
|
||||
time.Sleep(time.Second * 5) // maybe windows defender occupied the file, retry
|
||||
dst, errFiles = os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
||||
if errFiles != nil {
|
||||
gLog.e("os.OpenFile %s error:%s", targetPath, errFiles)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, errFiles = io.Copy(dst, src)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
|
||||
gLog.e("io.Copy error:%s", errFiles)
|
||||
return
|
||||
}
|
||||
src.Close()
|
||||
dst.Close()
|
||||
|
||||
// install system service
|
||||
err = d.Control("install", targetPath, []string{"-d"})
|
||||
err := d.Control("install", targetPath, []string{"-d"})
|
||||
if err == nil {
|
||||
gLog.Println(LvINFO, "install system service ok.")
|
||||
gLog.i("install system service ok.")
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
err = d.Control("start", targetPath, []string{"-d"})
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "start openp2p service error:", err)
|
||||
gLog.e("start openp2p service error:%s", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "start openp2p service ok.")
|
||||
gLog.i("start openp2p service ok.")
|
||||
}
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
gConf.save()
|
||||
gLog.i("Visit WebUI on https://console.openp2p.cn")
|
||||
}
|
||||
|
||||
func installByFilename() {
|
||||
@@ -78,7 +71,7 @@ func installByFilename() {
|
||||
}
|
||||
serverHost := params[1]
|
||||
token := params[2]
|
||||
gLog.Println(LvINFO, "install start")
|
||||
gLog.i("install start")
|
||||
targetPath := os.Args[0]
|
||||
args := []string{"install"}
|
||||
args = append(args, "-serverhost")
|
||||
@@ -93,31 +86,38 @@ func installByFilename() {
|
||||
cmd.Env = env
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "install by filename, start process error:", err)
|
||||
gLog.e("install by filename, start process error:%s", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LvINFO, "install end")
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
gLog.i("install end")
|
||||
gLog.i("Visit WebUI on https://console.openp2p.cn")
|
||||
fmt.Println("Press the Any Key to exit")
|
||||
fmt.Scanln()
|
||||
os.Exit(0)
|
||||
}
|
||||
func uninstall() {
|
||||
gLog.Println(LvINFO, "uninstall start")
|
||||
defer gLog.Println(LvINFO, "uninstall end")
|
||||
|
||||
func uninstall(rmFiles bool) {
|
||||
gLog.i("uninstall start")
|
||||
defer gLog.i("uninstall end")
|
||||
d := daemon{}
|
||||
err := d.Control("stop", "", nil)
|
||||
if err != nil { // service maybe not install
|
||||
return
|
||||
gLog.d("stop service error:%s", err)
|
||||
}
|
||||
err = d.Control("uninstall", "", nil)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "uninstall system service error:", err)
|
||||
gLog.d("uninstall system service error:%s", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "uninstall system service ok.")
|
||||
gLog.i("uninstall system service ok.")
|
||||
}
|
||||
time.Sleep(time.Second * 3)
|
||||
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
os.Remove(binPath + "0")
|
||||
os.Remove(binPath)
|
||||
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
||||
if rmFiles {
|
||||
if err := os.RemoveAll(defaultInstallPath); err != nil {
|
||||
gLog.e("RemoveAll %s error:%s", defaultInstallPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
195
core/log.go
195
core/log.go
@@ -3,38 +3,33 @@ package openp2p
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LogLevel int
|
||||
type LogLevel int32
|
||||
|
||||
var gLog *logger
|
||||
|
||||
const (
|
||||
LvDev LogLevel = -1
|
||||
LvDEBUG LogLevel = iota
|
||||
LvINFO
|
||||
LvWARN
|
||||
LvERROR
|
||||
LvDEBUG LogLevel = 0
|
||||
LvINFO LogLevel = 1
|
||||
LvWARN LogLevel = 2
|
||||
LvERROR LogLevel = 3
|
||||
)
|
||||
|
||||
var (
|
||||
logFileNames map[LogLevel]string
|
||||
loglevel map[LogLevel]string
|
||||
)
|
||||
|
||||
func init() {
|
||||
logFileNames = make(map[LogLevel]string)
|
||||
loglevel = make(map[LogLevel]string)
|
||||
logFileNames[0] = ".log"
|
||||
loglevel[LvDEBUG] = "DEBUG"
|
||||
loglevel[LvINFO] = "INFO"
|
||||
loglevel[LvWARN] = "WARN"
|
||||
loglevel[LvERROR] = "ERROR"
|
||||
loglevel[LvDev] = "Dev"
|
||||
const logFileNames string = ".log"
|
||||
|
||||
var loglevel = map[LogLevel]string{
|
||||
LvDEBUG: "DEBUG",
|
||||
LvINFO: "INFO",
|
||||
LvWARN: "WARN",
|
||||
LvERROR: "ERROR",
|
||||
LvDev: "Dev",
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -43,62 +38,54 @@ const (
|
||||
)
|
||||
|
||||
type logger struct {
|
||||
loggers map[LogLevel]*log.Logger
|
||||
files map[LogLevel]*os.File
|
||||
level LogLevel
|
||||
logDir string
|
||||
mtx *sync.Mutex
|
||||
lineEnding string
|
||||
pid int
|
||||
maxLogSize int64
|
||||
mode int
|
||||
stdLogger *log.Logger
|
||||
logger *log.Logger
|
||||
files *os.File
|
||||
level atomic.Int32
|
||||
logDir string
|
||||
mtx sync.Mutex
|
||||
lineEnding string
|
||||
pid int
|
||||
maxLogSize atomic.Int64
|
||||
mode int
|
||||
stdLogger *log.Logger
|
||||
checkFileRunning bool
|
||||
}
|
||||
|
||||
func NewLogger(path string, filePrefix string, level LogLevel, maxLogSize int64, mode int) *logger {
|
||||
loggers := make(map[LogLevel]*log.Logger)
|
||||
logfiles := make(map[LogLevel]*os.File)
|
||||
var (
|
||||
logdir string
|
||||
)
|
||||
if path == "" {
|
||||
logdir = "log/"
|
||||
} else {
|
||||
logdir = path + "/log/"
|
||||
logdir := filepath.Join(path, "log")
|
||||
if err := os.MkdirAll(logdir, 0755); err != nil && mode&LogFile != 0 {
|
||||
return nil
|
||||
}
|
||||
os.MkdirAll(logdir, 0777)
|
||||
for lv := range logFileNames {
|
||||
logFilePath := logdir + filePrefix + logFileNames[lv]
|
||||
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
os.Chmod(logFilePath, 0644)
|
||||
logfiles[lv] = f
|
||||
loggers[lv] = log.New(f, "", log.LstdFlags|log.Lmicroseconds)
|
||||
logFilePath := filepath.Join(logdir, filePrefix+logFileNames)
|
||||
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil && mode&LogFile != 0 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var le string
|
||||
stdLog := log.New(f, "", log.LstdFlags|log.Lmicroseconds)
|
||||
le := "\n"
|
||||
if runtime.GOOS == "windows" {
|
||||
le = "\r\n"
|
||||
} else {
|
||||
le = "\n"
|
||||
}
|
||||
pLog := &logger{loggers, logfiles, level, logdir, &sync.Mutex{}, le, os.Getpid(), maxLogSize, mode, log.New(os.Stdout, "", 0)}
|
||||
pLog := &logger{logger: stdLog,
|
||||
files: f,
|
||||
logDir: logdir,
|
||||
lineEnding: le,
|
||||
pid: os.Getpid(),
|
||||
mode: mode,
|
||||
stdLogger: log.New(os.Stdout, "", 0)}
|
||||
pLog.setMaxSize(maxLogSize)
|
||||
pLog.setLevel(level)
|
||||
pLog.stdLogger.SetFlags(log.LstdFlags | log.Lmicroseconds)
|
||||
go pLog.checkFile()
|
||||
return pLog
|
||||
}
|
||||
|
||||
func (l *logger) setLevel(level LogLevel) {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
l.level = level
|
||||
l.level.Store(int32(level))
|
||||
}
|
||||
|
||||
func (l *logger) setMaxSize(size int64) {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
l.maxLogSize = size
|
||||
l.maxLogSize.Store(size)
|
||||
}
|
||||
|
||||
func (l *logger) setMode(mode int) {
|
||||
@@ -107,49 +94,61 @@ func (l *logger) setMode(mode int) {
|
||||
l.mode = mode
|
||||
}
|
||||
|
||||
func (l *logger) close() {
|
||||
l.checkFileRunning = false
|
||||
l.files.Close()
|
||||
}
|
||||
|
||||
func (l *logger) checkFile() {
|
||||
if l.maxLogSize <= 0 {
|
||||
if l.maxLogSize.Load() <= 0 {
|
||||
return
|
||||
}
|
||||
l.checkFileRunning = true
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
for {
|
||||
for l.checkFileRunning {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
l.mtx.Lock()
|
||||
for lv, logFile := range l.files {
|
||||
f, e := logFile.Stat()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
if f.Size() <= l.maxLogSize {
|
||||
continue
|
||||
}
|
||||
logFile.Close()
|
||||
fname := f.Name()
|
||||
backupPath := l.logDir + fname + ".0"
|
||||
os.Remove(backupPath)
|
||||
os.Rename(l.logDir+fname, backupPath)
|
||||
newFile, e := os.OpenFile(l.logDir+fname, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if e == nil {
|
||||
l.loggers[lv].SetOutput(newFile)
|
||||
l.files[lv] = newFile
|
||||
}
|
||||
f, e := l.files.Stat()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
l.mtx.Unlock()
|
||||
if f.Size() <= l.maxLogSize.Load() {
|
||||
continue
|
||||
}
|
||||
l.mtx.Lock()
|
||||
l.files.Close()
|
||||
fname := f.Name()
|
||||
backupPath := filepath.Join(l.logDir, fname+".0")
|
||||
err := os.Remove(backupPath)
|
||||
if err != nil {
|
||||
log.Println("remove openp2p.log0 error:", err)
|
||||
}
|
||||
if err = os.Rename(filepath.Join(l.logDir, fname), backupPath); err != nil {
|
||||
log.Println("rename openp2p.log error:", err)
|
||||
}
|
||||
if newFile, e := os.OpenFile(filepath.Join(l.logDir, fname), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); e == nil {
|
||||
|
||||
l.logger.SetOutput(newFile)
|
||||
l.files = newFile
|
||||
l.mtx.Unlock()
|
||||
}
|
||||
case <-time.After(time.Second * 1):
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) Printf(level LogLevel, format string, params ...interface{}) {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
if level < l.level {
|
||||
if level < LogLevel(l.level.Load()) {
|
||||
return
|
||||
}
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
|
||||
pidAndLevel := []interface{}{l.pid, loglevel[level]}
|
||||
params = append(pidAndLevel, params...)
|
||||
if l.mode&LogFile != 0 {
|
||||
l.loggers[0].Printf("%d %s "+format+l.lineEnding, params...)
|
||||
l.logger.Printf("%d %s "+format+l.lineEnding, params...)
|
||||
}
|
||||
if l.mode&LogConsole != 0 {
|
||||
l.stdLogger.Printf("%d %s "+format+l.lineEnding, params...)
|
||||
@@ -157,18 +156,38 @@ func (l *logger) Printf(level LogLevel, format string, params ...interface{}) {
|
||||
}
|
||||
|
||||
func (l *logger) Println(level LogLevel, params ...interface{}) {
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
if level < l.level {
|
||||
if level < LogLevel(l.level.Load()) {
|
||||
return
|
||||
}
|
||||
l.mtx.Lock()
|
||||
defer l.mtx.Unlock()
|
||||
pidAndLevel := []interface{}{l.pid, " ", loglevel[level], " "}
|
||||
params = append(pidAndLevel, params...)
|
||||
params = append(params, l.lineEnding)
|
||||
if l.mode&LogFile != 0 {
|
||||
l.loggers[0].Print(params...)
|
||||
l.logger.Print(params...)
|
||||
}
|
||||
if l.mode&LogConsole != 0 {
|
||||
l.stdLogger.Print(params...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) d(format string, params ...interface{}) {
|
||||
l.Printf(LvDEBUG, format, params...)
|
||||
}
|
||||
|
||||
func (l *logger) i(format string, params ...interface{}) {
|
||||
l.Printf(LvINFO, format, params...)
|
||||
}
|
||||
|
||||
func (l *logger) w(format string, params ...interface{}) {
|
||||
l.Printf(LvWARN, format, params...)
|
||||
}
|
||||
|
||||
func (l *logger) e(format string, params ...interface{}) {
|
||||
l.Printf(LvERROR, format, params...)
|
||||
}
|
||||
|
||||
func (l *logger) dev(format string, params ...interface{}) {
|
||||
l.Printf(LvDev, format, params...)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func Run() {
|
||||
install()
|
||||
return
|
||||
case "uninstall":
|
||||
uninstall()
|
||||
uninstall(true)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,10 @@ import (
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
)
|
||||
|
||||
const optunMTU = 1420
|
||||
|
||||
var AndroidSDWANConfig chan []byte
|
||||
var preAndroidSDWANConfig string
|
||||
|
||||
type optun struct {
|
||||
tunName string
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
ReadTunBuffSize = 2048
|
||||
ReadTunBuffNum = 16
|
||||
)
|
||||
|
||||
var AndroidReadTun chan []byte // TODO: multi channel
|
||||
@@ -35,27 +37,35 @@ func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
func AndroidRead(data []byte, len int) {
|
||||
head := PacketHeader{}
|
||||
parseHeader(data, &head)
|
||||
gLog.Printf(LvDev, "AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
||||
// gLog.dev("AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
||||
buf := make([]byte, len)
|
||||
copy(buf, data)
|
||||
AndroidReadTun <- buf
|
||||
}
|
||||
|
||||
func AndroidWrite(buf []byte) int {
|
||||
p := <-AndroidWriteTun
|
||||
copy(buf, p)
|
||||
return len(p)
|
||||
func AndroidWrite(buf []byte, timeoutMs int) int {
|
||||
timeout := time.Duration(timeoutMs) * time.Millisecond
|
||||
select {
|
||||
case p := <-AndroidWriteTun:
|
||||
if len(p) > int(gConf.sdwan.Mtu) {
|
||||
gLog.e("AndroidWrite packet too large %d", len(p))
|
||||
}
|
||||
copy(buf, p)
|
||||
return len(p)
|
||||
case <-time.After(timeout):
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func GetAndroidSDWANConfig(buf []byte) int {
|
||||
p := <-AndroidSDWANConfig
|
||||
copy(buf, p)
|
||||
gLog.Printf(LvINFO, "AndroidSDWANConfig=%s", p)
|
||||
gLog.i("AndroidSDWANConfig=%s", p)
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func GetAndroidNodeName() string {
|
||||
gLog.Printf(LvINFO, "GetAndroidNodeName=%s", gConf.Network.Node)
|
||||
gLog.i("GetAndroidNodeName=%s", gConf.Network.Node)
|
||||
return gConf.Network.Node
|
||||
}
|
||||
|
||||
|
||||
10
core/udp.go
10
core/udp.go
@@ -22,7 +22,7 @@ func UDPRead(conn *net.UDPConn, timeout time.Duration) (ra net.Addr, head *openP
|
||||
if timeout > 0 {
|
||||
err = conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "SetReadDeadline error")
|
||||
gLog.e("SetReadDeadline error")
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
@@ -35,9 +35,13 @@ func UDPRead(conn *net.UDPConn, timeout time.Duration) (ra net.Addr, head *openP
|
||||
}
|
||||
head = &openP2PHeader{}
|
||||
err = binary.Read(bytes.NewReader(buff[:openP2PHeaderSize]), binary.LittleEndian, head)
|
||||
if err != nil || head.DataLen > uint32(len(buff)-openP2PHeaderSize) {
|
||||
gLog.Println(LvERROR, "parse p2pheader error:", err)
|
||||
if err != nil {
|
||||
gLog.e("parse p2pheader error:%s", err)
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
if head.DataLen > uint32(len(buff)-openP2PHeaderSize) {
|
||||
gLog.e("parse p2pheader error:%d", ErrHeaderDataLen)
|
||||
return nil, nil, nil, 0, ErrHeaderDataLen
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
10
core/upnp.go
10
core/upnp.go
@@ -63,13 +63,15 @@ func Discover() (nat NAT, err error) {
|
||||
return
|
||||
}
|
||||
var n int
|
||||
socket.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
_, _, err = socket.ReadFromUDP(answerBytes)
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "UPNP discover error:", err)
|
||||
gLog.d("UPNP discover error:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
socket.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
n, _, err = socket.ReadFromUDP(answerBytes)
|
||||
if err != nil {
|
||||
break
|
||||
@@ -266,7 +268,11 @@ func soapRequest(url, function, message, domain string) (r *http.Response, err e
|
||||
|
||||
// log.Stderr("soapRequest ", req)
|
||||
|
||||
r, err = http.DefaultClient.Do(req)
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
r, err = client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
var (
|
||||
defaultInstallPath = "/usr/local/openp2p"
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
|
||||
@@ -9,9 +9,12 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
var (
|
||||
defaultInstallPath = "/usr/local/openp2p"
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
|
||||
@@ -10,9 +10,12 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
var (
|
||||
defaultInstallPath = "/usr/local/openp2p"
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
|
||||
@@ -11,9 +11,12 @@ import (
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
const (
|
||||
var (
|
||||
defaultInstallPath = "C:\\Program Files\\OpenP2P"
|
||||
defaultBinName = "openp2p.exe"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBinName = "openp2p.exe"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
@@ -47,7 +50,7 @@ func setRLimit() error {
|
||||
func setFirewall() {
|
||||
fullPath, err := filepath.Abs(os.Args[0])
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "add firewall error:", err)
|
||||
gLog.e("add firewall error:%s", err)
|
||||
return
|
||||
}
|
||||
isXP := false
|
||||
|
||||
8
go.mod
8
go.mod
@@ -4,13 +4,15 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/openp2p-cn/go-reuseport v0.3.2
|
||||
github.com/openp2p-cn/service v1.0.0
|
||||
github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e
|
||||
github.com/openp2p-cn/wireguard-go v0.0.20241020
|
||||
github.com/quic-go/quic-go v0.34.0
|
||||
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
)
|
||||
@@ -33,9 +35,9 @@ require (
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93 // indirect
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user