Implement announcements on probing success
Once probing succeeds, the advertiser sends announcements for its records as per RFC6762 8.3. Implement MdnsRecordRepository.onProbingSucceeded to return the AnnouncementInfo which will be sent. Bug: 241738458 Test: atest Change-Id: Id4c2e610911fdf471a6d6ae08c2127fbf1530dc7
This commit is contained in:
@@ -22,11 +22,10 @@ import android.os.HandlerThread
|
||||
import android.os.SystemClock
|
||||
import com.android.internal.util.HexDump
|
||||
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
|
||||
import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||
import com.android.testutils.DevSdkIgnoreRunner
|
||||
import java.net.DatagramPacket
|
||||
import java.net.Inet6Address
|
||||
import java.net.InetAddress
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import org.junit.After
|
||||
@@ -150,8 +149,8 @@ class MdnsAnnouncerTest {
|
||||
val v6Addr1 = parseNumericAddress("2001:DB8::123")
|
||||
val v6Addr2 = parseNumericAddress("2001:DB8::456")
|
||||
val v4AddrRev = arrayOf("123", "0", "2", "192", "in-addr", "arpa")
|
||||
val v6Addr1Rev = getReverseV6AddressName(v6Addr1)
|
||||
val v6Addr2Rev = getReverseV6AddressName(v6Addr2)
|
||||
val v6Addr1Rev = getReverseDnsAddress(v6Addr1)
|
||||
val v6Addr2Rev = getReverseDnsAddress(v6Addr2)
|
||||
|
||||
val announcedRecords = listOf(
|
||||
// Reverse address records
|
||||
@@ -267,13 +266,3 @@ class MdnsAnnouncerTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.1.0.0.2.ip6.arpa
|
||||
*/
|
||||
private fun getReverseV6AddressName(addr: InetAddress): Array<String> {
|
||||
assertTrue(addr is Inet6Address)
|
||||
return addr.address.flatMapTo(mutableListOf("arpa", "ip6")) {
|
||||
HexDump.toHexString(it).toCharArray().map(Char::toString)
|
||||
}.reversed().toTypedArray()
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ class MdnsInterfaceAdvertiserTest {
|
||||
doReturn(testExitInfo).`when`(repository).exitService(TEST_SERVICE_ID_1)
|
||||
advertiser.removeService(TEST_SERVICE_ID_1)
|
||||
|
||||
verify(prober).stop(TEST_SERVICE_ID_1)
|
||||
verify(announcer).stop(TEST_SERVICE_ID_1)
|
||||
verify(announcer).startSending(TEST_SERVICE_ID_1, testExitInfo, EXIT_ANNOUNCEMENT_DELAY_MS)
|
||||
|
||||
// TODO: after exit announcements are implemented, verify that announceCb.onFinished causes
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package com.android.server.connectivity.mdns
|
||||
|
||||
import android.net.InetAddresses.parseNumericAddress
|
||||
import android.net.LinkAddress
|
||||
import android.net.nsd.NsdServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.HandlerThread
|
||||
import com.android.server.connectivity.mdns.MdnsRecordRepository.Dependencies
|
||||
import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress
|
||||
import com.android.testutils.DevSdkIgnoreRule
|
||||
import com.android.testutils.DevSdkIgnoreRunner
|
||||
import java.net.NetworkInterface
|
||||
@@ -39,10 +41,10 @@ private const val TEST_SERVICE_ID_1 = 42
|
||||
private const val TEST_SERVICE_ID_2 = 43
|
||||
private const val TEST_PORT = 12345
|
||||
private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
|
||||
private val TEST_ADDRESSES = arrayOf(
|
||||
parseNumericAddress("192.0.2.111"),
|
||||
parseNumericAddress("2001:db8::111"),
|
||||
parseNumericAddress("2001:db8::222"))
|
||||
private val TEST_ADDRESSES = listOf(
|
||||
LinkAddress(parseNumericAddress("192.0.2.111"), 24),
|
||||
LinkAddress(parseNumericAddress("2001:db8::111"), 64),
|
||||
LinkAddress(parseNumericAddress("2001:db8::222"), 64))
|
||||
|
||||
private val TEST_SERVICE_1 = NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
@@ -50,6 +52,12 @@ private val TEST_SERVICE_1 = NsdServiceInfo().apply {
|
||||
port = TEST_PORT
|
||||
}
|
||||
|
||||
private val TEST_SERVICE_2 = NsdServiceInfo().apply {
|
||||
serviceType = "_testservice._tcp"
|
||||
serviceName = "MyOtherTestService"
|
||||
port = TEST_PORT
|
||||
}
|
||||
|
||||
@RunWith(DevSdkIgnoreRunner::class)
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
class MdnsRecordRepositoryTest {
|
||||
@@ -57,7 +65,7 @@ class MdnsRecordRepositoryTest {
|
||||
private val deps = object : Dependencies() {
|
||||
override fun getHostname() = TEST_HOSTNAME
|
||||
override fun getInterfaceInetAddresses(iface: NetworkInterface) =
|
||||
Collections.enumeration(TEST_ADDRESSES.toList())
|
||||
Collections.enumeration(TEST_ADDRESSES.map { it.address })
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -112,6 +120,15 @@ class MdnsRecordRepositoryTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInvalidReuseOfServiceId() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps)
|
||||
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExitingServiceReAdded() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps)
|
||||
@@ -124,4 +141,131 @@ class MdnsRecordRepositoryTest {
|
||||
repository.removeService(TEST_SERVICE_ID_2)
|
||||
assertEquals(0, repository.servicesCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnProbingSucceeded() {
|
||||
val repository = MdnsRecordRepository(thread.looper, deps)
|
||||
repository.updateAddresses(TEST_ADDRESSES)
|
||||
|
||||
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
|
||||
val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
|
||||
val announcementInfo = repository.onProbingSucceeded(probingInfo)
|
||||
val packet = announcementInfo.getPacket(0)
|
||||
|
||||
assertEquals(0x8400 /* response, authoritative */, packet.flags)
|
||||
assertEquals(0, packet.questions.size)
|
||||
assertEquals(0, packet.authorityRecords.size)
|
||||
|
||||
val serviceType = arrayOf("_testservice", "_tcp", "local")
|
||||
val serviceName = arrayOf("MyTestService", "_testservice", "_tcp", "local")
|
||||
val v4AddrRev = getReverseDnsAddress(TEST_ADDRESSES[0].address)
|
||||
val v6Addr1Rev = getReverseDnsAddress(TEST_ADDRESSES[1].address)
|
||||
val v6Addr2Rev = getReverseDnsAddress(TEST_ADDRESSES[2].address)
|
||||
|
||||
assertContentEquals(listOf(
|
||||
// Reverse address and address records for the hostname
|
||||
MdnsPointerRecord(v4AddrRev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_HOSTNAME),
|
||||
MdnsInetAddressRecord(TEST_HOSTNAME,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_ADDRESSES[0].address),
|
||||
MdnsPointerRecord(v6Addr1Rev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_HOSTNAME),
|
||||
MdnsInetAddressRecord(TEST_HOSTNAME,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_ADDRESSES[1].address),
|
||||
MdnsPointerRecord(v6Addr2Rev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_HOSTNAME),
|
||||
MdnsInetAddressRecord(TEST_HOSTNAME,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_ADDRESSES[2].address),
|
||||
// Service registration records (RFC6763)
|
||||
MdnsPointerRecord(
|
||||
serviceType,
|
||||
0L /* receiptTimeMillis */,
|
||||
// Not a unique name owned by the announcer, so cacheFlush=false
|
||||
false /* cacheFlush */,
|
||||
4500000L /* ttlMillis */,
|
||||
serviceName),
|
||||
MdnsServiceRecord(
|
||||
serviceName,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
0 /* servicePriority */,
|
||||
0 /* serviceWeight */,
|
||||
TEST_PORT /* servicePort */,
|
||||
TEST_HOSTNAME),
|
||||
MdnsTextRecord(
|
||||
serviceName,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
4500000L /* ttlMillis */,
|
||||
emptyList() /* entries */),
|
||||
// Service type enumeration record (RFC6763 9.)
|
||||
MdnsPointerRecord(
|
||||
arrayOf("_services", "_dns-sd", "_udp", "local"),
|
||||
0L /* receiptTimeMillis */,
|
||||
false /* cacheFlush */,
|
||||
4500000L /* ttlMillis */,
|
||||
serviceType)
|
||||
), packet.answers)
|
||||
|
||||
assertContentEquals(listOf(
|
||||
MdnsNsecRecord(v4AddrRev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
v4AddrRev,
|
||||
intArrayOf(MdnsRecord.TYPE_PTR)),
|
||||
MdnsNsecRecord(TEST_HOSTNAME,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
TEST_HOSTNAME,
|
||||
intArrayOf(MdnsRecord.TYPE_A, MdnsRecord.TYPE_AAAA)),
|
||||
MdnsNsecRecord(v6Addr1Rev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
v6Addr1Rev,
|
||||
intArrayOf(MdnsRecord.TYPE_PTR)),
|
||||
MdnsNsecRecord(v6Addr2Rev,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
120000L /* ttlMillis */,
|
||||
v6Addr2Rev,
|
||||
intArrayOf(MdnsRecord.TYPE_PTR)),
|
||||
MdnsNsecRecord(serviceName,
|
||||
0L /* receiptTimeMillis */,
|
||||
true /* cacheFlush */,
|
||||
4500000L /* ttlMillis */,
|
||||
serviceName,
|
||||
intArrayOf(MdnsRecord.TYPE_TXT, MdnsRecord.TYPE_SRV))
|
||||
), packet.additionalRecords)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetReverseDnsAddress() {
|
||||
val expectedV6 = "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.1.0.0.2.ip6.arpa"
|
||||
.split(".").toTypedArray()
|
||||
assertContentEquals(expectedV6, getReverseDnsAddress(parseNumericAddress("2001:db8::1")))
|
||||
val expectedV4 = "123.2.0.192.in-addr.arpa".split(".").toTypedArray()
|
||||
assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123")))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user