update
This commit is contained in:
7 files changed
+138
-66
No files matched your search
@@ -1,9 +1,9 @@
|
||||
# native-mdns
|
||||
|
||||
A Kotlin multiplatform library for mdns announcer(mdns server), only broadcast is supported,
|
||||
it depends on ktor-network
|
||||
it depends on ktor-network.
|
||||
|
||||
support PTR.
|
||||
Also, nmdns can be compiled to shared/static lib for other language usage, see [build.gradle.kts](build.gradle.kts)
|
||||
|
||||
Supported platforms:
|
||||
1. windows64(mingwx64)
|
||||
@@ -12,6 +12,11 @@ Supported platforms:
|
||||
4. macosArm64
|
||||
5. jvm(11 or later)
|
||||
|
||||
Supported srv type
|
||||
1. A
|
||||
2. PTR
|
||||
|
||||
> AAAA is not supported
|
||||
|
||||
AirPlay2(_airplay._tcp.local.) is tested
|
||||
|
||||
@@ -35,7 +40,7 @@ kotlin {
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation("cn.rtast.nmdns:native-mdns:0.0.1")
|
||||
implementation("cn.rtast.nmdns:native-mdns:0.0.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +49,7 @@ kotlin {
|
||||
There is a simple airplay2 service
|
||||
|
||||
```kotlin
|
||||
val service = createService(
|
||||
val service = registerService(
|
||||
serviceType = "_airplay._tcp.local.",
|
||||
serviceName = "AP@RTAST",
|
||||
hostname = "rtakland.local.",
|
||||
@@ -52,9 +57,9 @@ There is a simple airplay2 service
|
||||
port = 7001,
|
||||
bindAddress = "192.168.10.104",
|
||||
mdnsPort = 5356,
|
||||
)
|
||||
while (true) {
|
||||
)
|
||||
while (true) {
|
||||
service.broadcast()
|
||||
delay(2000L)
|
||||
}
|
||||
delay(2000L) // or use cn.rtast.nmdns.sleep1(2) sleep 2 seconds
|
||||
}
|
||||
```
|
||||
+41
-4
@@ -6,19 +6,32 @@ plugins {
|
||||
}
|
||||
|
||||
group = "cn.rtast.nmdns"
|
||||
version = "0.0.1"
|
||||
version = "0.0.2"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
linuxArm64()
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
val nativeTargets = listOf(
|
||||
linuxArm64(),
|
||||
linuxX64(),
|
||||
mingwX64(),
|
||||
macosArm64()
|
||||
)
|
||||
jvm { compilerOptions { jvmTarget = JvmTarget.JVM_11 } }
|
||||
|
||||
nativeTargets.forEach {
|
||||
it.binaries {
|
||||
staticLib {
|
||||
baseName = "nmdns"
|
||||
}
|
||||
sharedLib {
|
||||
baseName = "nmdns"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation("io.ktor:ktor-network:3.2.3")
|
||||
@@ -42,3 +55,27 @@ publishing {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* link all targets static lib
|
||||
* Apple target can only be compiled on macos
|
||||
*/
|
||||
tasks.register("linkStaticLibrary") {
|
||||
group = "nmdns"
|
||||
dependsOn(tasks.named("linkReleaseStaticLinuxArm64"))
|
||||
dependsOn(tasks.named("linkReleaseStaticLinuxX64"))
|
||||
dependsOn(tasks.named("linkReleaseStaticMacosArm64"))
|
||||
dependsOn(tasks.named("linkReleaseStaticMingwX64"))
|
||||
}
|
||||
|
||||
/**
|
||||
* link all targrts to shared lib
|
||||
* Apple target can only be compiled on macos
|
||||
*/
|
||||
tasks.register("linkSharedLibrary") {
|
||||
group = "nmdns"
|
||||
dependsOn(tasks.named("linkReleaseSharedLinuxArm64"))
|
||||
dependsOn(tasks.named("linkReleaseSharedLinuxX64"))
|
||||
dependsOn(tasks.named("linkReleaseSharedMacosArm64"))
|
||||
dependsOn(tasks.named("linkReleaseSharedMingwX64"))
|
||||
}
|
||||
@@ -40,4 +40,7 @@ private val macAddresses = listOf(
|
||||
"c3:c9:1c:3d:ae:dd"
|
||||
)
|
||||
|
||||
/**
|
||||
* get random mac address
|
||||
*/
|
||||
fun randomMacAddress(): String = macAddresses.random()
|
||||
+42
-34
@@ -13,58 +13,62 @@ import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.io.Buffer
|
||||
|
||||
data class NMDNSServer(
|
||||
data class NMDNSAnnouncer(
|
||||
/**
|
||||
* coroutine dispatcher for running server
|
||||
*/
|
||||
val dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||
internal val dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||
/**
|
||||
* service type
|
||||
* default airplay
|
||||
* airplay service type: _airplay._tcp.local.
|
||||
*/
|
||||
val serviceType: String = "_airplay._tcp.local.",
|
||||
internal val serviceType: String,
|
||||
/**
|
||||
* service name
|
||||
* finally: $serviceName.$serviceType
|
||||
*/
|
||||
val serviceName: String = "APS",
|
||||
internal val serviceName: String,
|
||||
/**
|
||||
* local hostname
|
||||
*/
|
||||
val hostname: String,
|
||||
internal val hostname: String,
|
||||
/**
|
||||
* service ip, lan ip mostly
|
||||
*/
|
||||
val ipAddress: String,
|
||||
internal val ipAddress: String,
|
||||
/**
|
||||
* service port
|
||||
*/
|
||||
val port: Int = 7004,
|
||||
internal val port: Int = 7004,
|
||||
/**
|
||||
* mdns server port
|
||||
*/
|
||||
val mdnsPort: Int = 3025,
|
||||
internal val mdnsPort: Int = 3025,
|
||||
/**
|
||||
* Txt record content
|
||||
* txt record content
|
||||
*/
|
||||
val txtRecords: List<String> = listOf(
|
||||
"deviceid=01:23:45:67:89:AB",
|
||||
"model=AppleTV3,2C",
|
||||
"features=0x5A7FFFF7,0x1E",
|
||||
"srcvers=220.68",
|
||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
),
|
||||
internal val txtRecords: List<String>,
|
||||
/**
|
||||
* mdns socket server
|
||||
*/
|
||||
val server: BoundDatagramSocket,
|
||||
internal val server: BoundDatagramSocket,
|
||||
/**
|
||||
* srv packet
|
||||
*/
|
||||
val packet: Buffer,
|
||||
internal val packet: Buffer,
|
||||
)
|
||||
|
||||
suspend fun createService(
|
||||
/**
|
||||
* register service
|
||||
* airplay2 txt records
|
||||
* listOf(
|
||||
* "deviceid=${randomMacAddress()}",
|
||||
* "model=AppleTV3,2C",
|
||||
* "features=0x5A7FFFF7,0x1E",
|
||||
* "srcvers=220.68",
|
||||
* "pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
* )
|
||||
*/
|
||||
suspend fun registerService(
|
||||
serviceType: String,
|
||||
serviceName: String,
|
||||
hostname: String,
|
||||
@@ -72,25 +76,29 @@ suspend fun createService(
|
||||
port: Int,
|
||||
mdnsPort: Int = 9872,
|
||||
bindAddress: String,
|
||||
txtRecords: List<String> = listOf(
|
||||
"deviceid=${randomMacAddress()}",
|
||||
"model=AppleTV3,2C",
|
||||
"features=0x5A7FFFF7,0x1E",
|
||||
"srcvers=220.68",
|
||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
),
|
||||
): NMDNSServer {
|
||||
txtRecords: List<String>,
|
||||
): NMDNSAnnouncer {
|
||||
val manager = SelectorManager(Dispatchers.Default)
|
||||
val serverSocket = aSocket(manager).udp()
|
||||
.bind(InetSocketAddress(bindAddress, mdnsPort))
|
||||
return NMDNSServer(
|
||||
Dispatchers.Default, serviceType, serviceName,
|
||||
hostname, ipAddress, port, mdnsPort,
|
||||
txtRecords, serverSocket, buildPacket(serviceType, "$serviceName.$serviceType", hostname, ipAddress, port, txtRecords)
|
||||
return NMDNSAnnouncer(
|
||||
Dispatchers.Default,
|
||||
serviceType,
|
||||
serviceName,
|
||||
hostname,
|
||||
ipAddress,
|
||||
port,
|
||||
mdnsPort,
|
||||
txtRecords,
|
||||
serverSocket,
|
||||
buildPacket(serviceType, "$serviceName.$serviceType", hostname, ipAddress, port, txtRecords)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun NMDNSServer.broadcast() {
|
||||
/**
|
||||
* broadcast packet
|
||||
*/
|
||||
suspend fun NMDNSAnnouncer.broadcast() {
|
||||
this.server.send(Datagram(packet.copy(), InetSocketAddress("224.0.0.251", 5353)))
|
||||
}
|
||||
|
||||
@@ -7,4 +7,8 @@
|
||||
|
||||
package cn.rtast.nmdns
|
||||
|
||||
/**
|
||||
* block current thread
|
||||
* unit: second
|
||||
*/
|
||||
internal expect fun sleep1(time: Int)
|
||||
@@ -8,7 +8,8 @@
|
||||
package test
|
||||
|
||||
import cn.rtast.nmdns.broadcast
|
||||
import cn.rtast.nmdns.createService
|
||||
import cn.rtast.nmdns.randomMacAddress
|
||||
import cn.rtast.nmdns.registerService
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
@@ -40,14 +41,21 @@ class JvmTest {
|
||||
// println("sent")
|
||||
// delay(2000L)
|
||||
// }
|
||||
val service = createService(
|
||||
val service = registerService(
|
||||
serviceType = "_airplay._tcp.local.",
|
||||
serviceName = "AP@RTAST",
|
||||
hostname = "rtakland.local.",
|
||||
ipAddress = "192.168.10.104",
|
||||
port = 7001,
|
||||
bindAddress = "192.168.10.104",
|
||||
mdnsPort = 5356
|
||||
mdnsPort = 5356,
|
||||
txtRecords = listOf(
|
||||
"deviceid=${randomMacAddress()}",
|
||||
"model=AppleTV3,2C",
|
||||
"features=0x5A7FFFF7,0x1E",
|
||||
"srcvers=220.68",
|
||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
)
|
||||
)
|
||||
while (true) {
|
||||
service.broadcast()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* Copyright © 2025 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 9/29/25
|
||||
*/
|
||||
* Copyright © 2025 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 9/29/25
|
||||
*/
|
||||
|
||||
|
||||
package test
|
||||
|
||||
import cn.rtast.nmdns.broadcast
|
||||
import cn.rtast.nmdns.createService
|
||||
import cn.rtast.nmdns.randomMacAddress
|
||||
import cn.rtast.nmdns.registerService
|
||||
import cn.rtast.nmdns.sleep1
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.Test
|
||||
|
||||
@@ -18,14 +18,21 @@ class LinuxTest {
|
||||
@Test
|
||||
fun `test on linux`() {
|
||||
runBlocking {
|
||||
val service = createService(
|
||||
val service = registerService(
|
||||
serviceType = "_airplay._tcp.local.",
|
||||
serviceName = "AP@RTAST",
|
||||
hostname = "rtakland.local.",
|
||||
ipAddress = "192.168.10.104",
|
||||
port = 7001,
|
||||
bindAddress = "192.168.10.104",
|
||||
mdnsPort = 5356
|
||||
mdnsPort = 5356,
|
||||
txtRecords = listOf(
|
||||
"deviceid=${randomMacAddress()}",
|
||||
"model=AppleTV3,2C",
|
||||
"features=0x5A7FFFF7,0x1E",
|
||||
"srcvers=220.68",
|
||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
||||
)
|
||||
)
|
||||
while (true) {
|
||||
service.broadcast()
|
||||
|
||||
Reference in New Issue
Block a user