Remove ktor-network dependency use native socket
This commit is contained in:
21 files changed
+649
-179
No files matched your search
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright © 2025 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 9/30/25
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.nmdns
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@RequiresOptIn
|
||||
public annotation class CExport
|
||||
@@ -7,40 +7,16 @@
|
||||
|
||||
package cn.rtast.nmdns
|
||||
|
||||
private val macAddresses = listOf(
|
||||
"ef:42:0d:76:f1:97",
|
||||
"b4:91:7c:be:84:7b",
|
||||
"38:d0:d3:f5:63:d1",
|
||||
"90:d0:d5:3e:5b:fa",
|
||||
"4d:84:d4:dd:7e:b4",
|
||||
"11:1c:fb:06:6a:4a",
|
||||
"cf:97:be:b3:18:5b",
|
||||
"0c:34:bf:d8:55:71",
|
||||
"95:a0:71:10:31:ab",
|
||||
"4c:33:b8:4a:60:8e",
|
||||
"fc:89:a5:f2:b6:3c",
|
||||
"a7:42:99:34:b5:21",
|
||||
"9a:55:3f:5d:bb:9d",
|
||||
"2b:35:ce:77:a0:7c",
|
||||
"7d:51:21:72:c5:b4",
|
||||
"79:7d:cc:e1:30:9b",
|
||||
"aa:a2:cf:b5:e3:3c",
|
||||
"8d:73:3f:8e:ef:d7",
|
||||
"21:3c:a4:56:80:c5",
|
||||
"c1:fa:ca:cb:ec:f3",
|
||||
"51:76:e2:12:2f:af",
|
||||
"a8:03:22:2d:b9:80",
|
||||
"2a:84:3b:ad:9c:d9",
|
||||
"24:79:c3:ab:0f:b5",
|
||||
"bc:44:e3:c4:9e:be",
|
||||
"cb:1b:84:c2:94:ba",
|
||||
"9d:66:ce:d2:6e:4f",
|
||||
"43:bf:e2:b2:e3:78",
|
||||
"48:25:03:bb:9d:35",
|
||||
"c3:c9:1c:3d:ae:dd"
|
||||
)
|
||||
import kotlin.experimental.ExperimentalNativeApi
|
||||
import kotlin.native.CName
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* get random mac address
|
||||
* generate random mac address
|
||||
*/
|
||||
fun randomMacAddress(): String = macAddresses.random()
|
||||
@OptIn(ExperimentalNativeApi::class)
|
||||
@CName("random_mac_address")
|
||||
public fun randomMacAddress(): String {
|
||||
val bytes = ByteArray(6) { Random.nextInt(0, 256).toByte() }
|
||||
return bytes.joinToString(":") { it.toHexString() }
|
||||
}
|
||||
+63
-29
@@ -5,19 +5,14 @@
|
||||
*/
|
||||
|
||||
|
||||
@file:OptIn(ExperimentalNativeApi::class)
|
||||
|
||||
package cn.rtast.nmdns
|
||||
|
||||
import io.ktor.network.selector.*
|
||||
import io.ktor.network.sockets.*
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.io.Buffer
|
||||
import kotlin.experimental.ExperimentalNativeApi
|
||||
import kotlin.native.CName
|
||||
|
||||
data class NMDNSAnnouncer(
|
||||
/**
|
||||
* coroutine dispatcher for running server
|
||||
*/
|
||||
internal val dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||
public data class NMDNSAnnouncer(
|
||||
/**
|
||||
* service type
|
||||
* airplay service type: _airplay._tcp.local.
|
||||
@@ -50,12 +45,60 @@ data class NMDNSAnnouncer(
|
||||
/**
|
||||
* mdns socket server
|
||||
*/
|
||||
internal val server: BoundDatagramSocket,
|
||||
internal val server: Socket1,
|
||||
/**
|
||||
* srv packet
|
||||
*/
|
||||
internal val packet: Buffer,
|
||||
)
|
||||
internal val packet: ByteArray,
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as NMDNSAnnouncer
|
||||
|
||||
if (port != other.port) return false
|
||||
if (mdnsPort != other.mdnsPort) return false
|
||||
if (serviceType != other.serviceType) return false
|
||||
if (serviceName != other.serviceName) return false
|
||||
if (hostname != other.hostname) return false
|
||||
if (ipAddress != other.ipAddress) return false
|
||||
if (txtRecords != other.txtRecords) return false
|
||||
if (server != other.server) return false
|
||||
if (!packet.contentEquals(other.packet)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = port
|
||||
result = 31 * result + mdnsPort
|
||||
result = 31 * result + serviceType.hashCode()
|
||||
result = 31 * result + serviceName.hashCode()
|
||||
result = 31 * result + hostname.hashCode()
|
||||
result = 31 * result + ipAddress.hashCode()
|
||||
result = 31 * result + txtRecords.hashCode()
|
||||
result = 31 * result + server.hashCode()
|
||||
result = 31 * result + packet.contentHashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* broadcast packet
|
||||
*/
|
||||
public fun broadcast() {
|
||||
this.server.send(packet)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* export for c
|
||||
*/
|
||||
@CExport
|
||||
@CName("broadcast")
|
||||
public fun broadcast1(server: NMDNSAnnouncer) {
|
||||
server.server.send(server.packet)
|
||||
}
|
||||
|
||||
/**
|
||||
* register service
|
||||
@@ -68,7 +111,8 @@ data class NMDNSAnnouncer(
|
||||
* "pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
* )
|
||||
*/
|
||||
suspend fun registerService(
|
||||
@CName("register_service")
|
||||
public fun registerService(
|
||||
serviceType: String,
|
||||
serviceName: String,
|
||||
hostname: String,
|
||||
@@ -78,11 +122,9 @@ suspend fun registerService(
|
||||
bindAddress: String,
|
||||
txtRecords: List<String>,
|
||||
): NMDNSAnnouncer {
|
||||
val manager = SelectorManager(Dispatchers.Default)
|
||||
val serverSocket = aSocket(manager).udp()
|
||||
.bind(InetSocketAddress(bindAddress, mdnsPort))
|
||||
val server = createSocket()
|
||||
.bind(bindAddress, port)
|
||||
return NMDNSAnnouncer(
|
||||
Dispatchers.Default,
|
||||
serviceType,
|
||||
serviceName,
|
||||
hostname,
|
||||
@@ -90,18 +132,11 @@ suspend fun registerService(
|
||||
port,
|
||||
mdnsPort,
|
||||
txtRecords,
|
||||
serverSocket,
|
||||
server,
|
||||
buildPacket(serviceType, "$serviceName.$serviceType", hostname, ipAddress, port, txtRecords)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* broadcast packet
|
||||
*/
|
||||
suspend fun NMDNSAnnouncer.broadcast() {
|
||||
this.server.send(Datagram(packet.copy(), InetSocketAddress("224.0.0.251", 5353)))
|
||||
}
|
||||
|
||||
internal fun buildPacket(
|
||||
serviceType: String,
|
||||
serviceName: String,
|
||||
@@ -109,7 +144,7 @@ internal fun buildPacket(
|
||||
ip: String,
|
||||
port: Int,
|
||||
txtRecords: List<String>,
|
||||
): Buffer {
|
||||
): ByteArray {
|
||||
val records = mutableListOf<ByteArray>()
|
||||
records += encodeRR(serviceType, 12, encodeName(serviceName))
|
||||
|
||||
@@ -133,8 +168,7 @@ internal fun buildPacket(
|
||||
header[6] = ((records.size shr 8) and 0xFF).toByte()
|
||||
header[7] = (records.size and 0xFF).toByte()
|
||||
|
||||
val buffer = Buffer().apply { write(header + records.reduce { acc, r -> acc + r }) }
|
||||
return buffer
|
||||
return header + records.reduce { acc, r -> acc + r }
|
||||
}
|
||||
|
||||
internal fun encodeRR(name: String, type: Int, data: ByteArray): ByteArray {
|
||||
@@ -11,4 +11,5 @@ package cn.rtast.nmdns
|
||||
* block current thread
|
||||
* unit: second
|
||||
*/
|
||||
internal expect fun sleep1(time: Int)
|
||||
|
||||
public expect fun sleep1(time: Int)
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright © 2025 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 9/30/25
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
|
||||
package cn.rtast.nmdns
|
||||
|
||||
public expect class Socket1 internal constructor() {
|
||||
/**
|
||||
* bind to ip
|
||||
*/
|
||||
public fun bind(ip: String, port: Int): Socket1
|
||||
|
||||
/**
|
||||
* send packet
|
||||
*/
|
||||
public fun send(packet: ByteArray)
|
||||
|
||||
/**
|
||||
* close
|
||||
*/
|
||||
public fun destroy()
|
||||
}
|
||||
|
||||
internal fun createSocket(): Socket1 = Socket1()
|
||||
|
||||
public fun htons(value: UShort): UShort =
|
||||
(((value.toInt() and 0xFF) shl 8) or ((value.toInt() ushr 8) and 0xFF)).toUShort()
|
||||
|
||||
public fun htonl(value: UInt): UInt =
|
||||
((value and 0xFFu) shl 24) or
|
||||
((value and 0xFF00u) shl 8) or
|
||||
((value and 0xFF0000u) shr 8) or
|
||||
((value and 0xFF000000u) shr 24)
|
||||
Reference in New Issue
Block a user