update
This commit is contained in:
7 files changed
+138
-66
No files matched your search
@@ -1,9 +1,9 @@
|
|||||||
# native-mdns
|
# native-mdns
|
||||||
|
|
||||||
A Kotlin multiplatform library for mdns announcer(mdns server), only broadcast is supported,
|
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:
|
Supported platforms:
|
||||||
1. windows64(mingwx64)
|
1. windows64(mingwx64)
|
||||||
@@ -12,6 +12,11 @@ Supported platforms:
|
|||||||
4. macosArm64
|
4. macosArm64
|
||||||
5. jvm(11 or later)
|
5. jvm(11 or later)
|
||||||
|
|
||||||
|
Supported srv type
|
||||||
|
1. A
|
||||||
|
2. PTR
|
||||||
|
|
||||||
|
> AAAA is not supported
|
||||||
|
|
||||||
AirPlay2(_airplay._tcp.local.) is tested
|
AirPlay2(_airplay._tcp.local.) is tested
|
||||||
|
|
||||||
@@ -35,7 +40,7 @@ kotlin {
|
|||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
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
|
There is a simple airplay2 service
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
val service = createService(
|
val service = registerService(
|
||||||
serviceType = "_airplay._tcp.local.",
|
serviceType = "_airplay._tcp.local.",
|
||||||
serviceName = "AP@RTAST",
|
serviceName = "AP@RTAST",
|
||||||
hostname = "rtakland.local.",
|
hostname = "rtakland.local.",
|
||||||
@@ -55,6 +60,6 @@ There is a simple airplay2 service
|
|||||||
)
|
)
|
||||||
while (true) {
|
while (true) {
|
||||||
service.broadcast()
|
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"
|
group = "cn.rtast.nmdns"
|
||||||
version = "0.0.1"
|
version = "0.0.2"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
linuxArm64()
|
val nativeTargets = listOf(
|
||||||
linuxX64()
|
linuxArm64(),
|
||||||
mingwX64()
|
linuxX64(),
|
||||||
|
mingwX64(),
|
||||||
macosArm64()
|
macosArm64()
|
||||||
|
)
|
||||||
jvm { compilerOptions { jvmTarget = JvmTarget.JVM_11 } }
|
jvm { compilerOptions { jvmTarget = JvmTarget.JVM_11 } }
|
||||||
|
|
||||||
|
nativeTargets.forEach {
|
||||||
|
it.binaries {
|
||||||
|
staticLib {
|
||||||
|
baseName = "nmdns"
|
||||||
|
}
|
||||||
|
sharedLib {
|
||||||
|
baseName = "nmdns"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation("io.ktor:ktor-network:3.2.3")
|
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"
|
"c3:c9:1c:3d:ae:dd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get random mac address
|
||||||
|
*/
|
||||||
fun randomMacAddress(): String = macAddresses.random()
|
fun randomMacAddress(): String = macAddresses.random()
|
||||||
+42
-34
@@ -13,58 +13,62 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.io.Buffer
|
import kotlinx.io.Buffer
|
||||||
|
|
||||||
data class NMDNSServer(
|
data class NMDNSAnnouncer(
|
||||||
/**
|
/**
|
||||||
* coroutine dispatcher for running server
|
* coroutine dispatcher for running server
|
||||||
*/
|
*/
|
||||||
val dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
internal val dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||||
/**
|
/**
|
||||||
* service type
|
* service type
|
||||||
* default airplay
|
* airplay service type: _airplay._tcp.local.
|
||||||
*/
|
*/
|
||||||
val serviceType: String = "_airplay._tcp.local.",
|
internal val serviceType: String,
|
||||||
/**
|
/**
|
||||||
* service name
|
* service name
|
||||||
* finally: $serviceName.$serviceType
|
|
||||||
*/
|
*/
|
||||||
val serviceName: String = "APS",
|
internal val serviceName: String,
|
||||||
/**
|
/**
|
||||||
* local hostname
|
* local hostname
|
||||||
*/
|
*/
|
||||||
val hostname: String,
|
internal val hostname: String,
|
||||||
/**
|
/**
|
||||||
* service ip, lan ip mostly
|
* service ip, lan ip mostly
|
||||||
*/
|
*/
|
||||||
val ipAddress: String,
|
internal val ipAddress: String,
|
||||||
/**
|
/**
|
||||||
* service port
|
* service port
|
||||||
*/
|
*/
|
||||||
val port: Int = 7004,
|
internal val port: Int = 7004,
|
||||||
/**
|
/**
|
||||||
* mdns server port
|
* mdns server port
|
||||||
*/
|
*/
|
||||||
val mdnsPort: Int = 3025,
|
internal val mdnsPort: Int = 3025,
|
||||||
/**
|
/**
|
||||||
* Txt record content
|
* txt record content
|
||||||
*/
|
*/
|
||||||
val txtRecords: List<String> = listOf(
|
internal val txtRecords: List<String>,
|
||||||
"deviceid=01:23:45:67:89:AB",
|
|
||||||
"model=AppleTV3,2C",
|
|
||||||
"features=0x5A7FFFF7,0x1E",
|
|
||||||
"srcvers=220.68",
|
|
||||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
|
||||||
),
|
|
||||||
/**
|
/**
|
||||||
* mdns socket server
|
* mdns socket server
|
||||||
*/
|
*/
|
||||||
val server: BoundDatagramSocket,
|
internal val server: BoundDatagramSocket,
|
||||||
/**
|
/**
|
||||||
* srv packet
|
* 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,
|
serviceType: String,
|
||||||
serviceName: String,
|
serviceName: String,
|
||||||
hostname: String,
|
hostname: String,
|
||||||
@@ -72,25 +76,29 @@ suspend fun createService(
|
|||||||
port: Int,
|
port: Int,
|
||||||
mdnsPort: Int = 9872,
|
mdnsPort: Int = 9872,
|
||||||
bindAddress: String,
|
bindAddress: String,
|
||||||
txtRecords: List<String> = listOf(
|
txtRecords: List<String>,
|
||||||
"deviceid=${randomMacAddress()}",
|
): NMDNSAnnouncer {
|
||||||
"model=AppleTV3,2C",
|
|
||||||
"features=0x5A7FFFF7,0x1E",
|
|
||||||
"srcvers=220.68",
|
|
||||||
"pk=f3769a660475d27b4f6040381d784645e13e21c53e6d2da6a8c3d757086fc336"
|
|
||||||
),
|
|
||||||
): NMDNSServer {
|
|
||||||
val manager = SelectorManager(Dispatchers.Default)
|
val manager = SelectorManager(Dispatchers.Default)
|
||||||
val serverSocket = aSocket(manager).udp()
|
val serverSocket = aSocket(manager).udp()
|
||||||
.bind(InetSocketAddress(bindAddress, mdnsPort))
|
.bind(InetSocketAddress(bindAddress, mdnsPort))
|
||||||
return NMDNSServer(
|
return NMDNSAnnouncer(
|
||||||
Dispatchers.Default, serviceType, serviceName,
|
Dispatchers.Default,
|
||||||
hostname, ipAddress, port, mdnsPort,
|
serviceType,
|
||||||
txtRecords, serverSocket, buildPacket(serviceType, "$serviceName.$serviceType", hostname, ipAddress, port, txtRecords)
|
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)))
|
this.server.send(Datagram(packet.copy(), InetSocketAddress("224.0.0.251", 5353)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,4 +7,8 @@
|
|||||||
|
|
||||||
package cn.rtast.nmdns
|
package cn.rtast.nmdns
|
||||||
|
|
||||||
|
/**
|
||||||
|
* block current thread
|
||||||
|
* unit: second
|
||||||
|
*/
|
||||||
internal expect fun sleep1(time: Int)
|
internal expect fun sleep1(time: Int)
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import cn.rtast.nmdns.broadcast
|
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.delay
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -40,14 +41,21 @@ class JvmTest {
|
|||||||
// println("sent")
|
// println("sent")
|
||||||
// delay(2000L)
|
// delay(2000L)
|
||||||
// }
|
// }
|
||||||
val service = createService(
|
val service = registerService(
|
||||||
serviceType = "_airplay._tcp.local.",
|
serviceType = "_airplay._tcp.local.",
|
||||||
serviceName = "AP@RTAST",
|
serviceName = "AP@RTAST",
|
||||||
hostname = "rtakland.local.",
|
hostname = "rtakland.local.",
|
||||||
ipAddress = "192.168.10.104",
|
ipAddress = "192.168.10.104",
|
||||||
port = 7001,
|
port = 7001,
|
||||||
bindAddress = "192.168.10.104",
|
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) {
|
while (true) {
|
||||||
service.broadcast()
|
service.broadcast()
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import cn.rtast.nmdns.broadcast
|
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 cn.rtast.nmdns.sleep1
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
@@ -18,14 +18,21 @@ class LinuxTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test on linux`() {
|
fun `test on linux`() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val service = createService(
|
val service = registerService(
|
||||||
serviceType = "_airplay._tcp.local.",
|
serviceType = "_airplay._tcp.local.",
|
||||||
serviceName = "AP@RTAST",
|
serviceName = "AP@RTAST",
|
||||||
hostname = "rtakland.local.",
|
hostname = "rtakland.local.",
|
||||||
ipAddress = "192.168.10.104",
|
ipAddress = "192.168.10.104",
|
||||||
port = 7001,
|
port = 7001,
|
||||||
bindAddress = "192.168.10.104",
|
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) {
|
while (true) {
|
||||||
service.broadcast()
|
service.broadcast()
|
||||||
|
|||||||
Reference in New Issue
Block a user