diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java index cc08ea1acb..5f27b6a26b 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java @@ -253,8 +253,9 @@ public class MdnsAdvertiser { int getConflictingService(@NonNull NsdServiceInfo info) { for (int i = 0; i < mPendingRegistrations.size(); i++) { final NsdServiceInfo other = mPendingRegistrations.valueAt(i).getServiceInfo(); - if (info.getServiceName().equals(other.getServiceName()) - && info.getServiceType().equals(other.getServiceType())) { + if (MdnsUtils.equalsIgnoreDnsCase(info.getServiceName(), other.getServiceName()) + && MdnsUtils.equalsIgnoreDnsCase(info.getServiceType(), + other.getServiceType())) { return mPendingRegistrations.keyAt(i); } } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java index 2281c81f75..c7b93e5041 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java @@ -30,6 +30,7 @@ import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.SharedLog; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.ArrayList; @@ -56,21 +57,26 @@ public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback { public void put(@NonNull String serviceType, @Nullable Network network, @NonNull MdnsServiceTypeClient client) { - final Pair perNetworkServiceType = new Pair<>(serviceType, network); + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); + final Pair perNetworkServiceType = new Pair<>(dnsLowerServiceType, + network); clients.put(perNetworkServiceType, client); } @Nullable public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) { - final Pair perNetworkServiceType = new Pair<>(serviceType, network); + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); + final Pair perNetworkServiceType = new Pair<>(dnsLowerServiceType, + network); return clients.getOrDefault(perNetworkServiceType, null); } public List getByServiceType(@NonNull String serviceType) { + final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType); final List list = new ArrayList<>(); for (int i = 0; i < clients.size(); i++) { final Pair perNetworkServiceType = clients.keyAt(i); - if (serviceType.equals(perNetworkServiceType.first)) { + if (dnsLowerServiceType.equals(perNetworkServiceType.first)) { list.add(clients.valueAt(i)); } } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java index 6ec2f99582..1239180149 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsNsecRecord.java @@ -20,6 +20,7 @@ import android.net.DnsResolver; import android.text.TextUtils; import com.android.net.module.util.CollectionUtils; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.ArrayList; @@ -152,7 +153,8 @@ public class MdnsNsecRecord extends MdnsRecord { @Override public int hashCode() { return Objects.hash(super.hashCode(), - Arrays.hashCode(mNextDomain), Arrays.hashCode(mTypes)); + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(mNextDomain)), + Arrays.hashCode(mTypes)); } @Override @@ -165,7 +167,8 @@ public class MdnsNsecRecord extends MdnsRecord { } return super.equals(other) - && Arrays.equals(mNextDomain, ((MdnsNsecRecord) other).mNextDomain) + && MdnsUtils.equalsDnsLabelIgnoreDnsCase(mNextDomain, + ((MdnsNsecRecord) other).mNextDomain) && Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes); } } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java index c0f9b8b5b0..6879a64daa 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketWriter.java @@ -17,11 +17,11 @@ package com.android.server.connectivity.mdns; import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.net.DatagramPacket; import java.net.SocketAddress; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -180,7 +180,7 @@ public class MdnsPacketWriter { int existingOffset = entry.getKey(); String[] existingLabels = entry.getValue(); - if (Arrays.equals(existingLabels, labels)) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(existingLabels, labels)) { writePointer(existingOffset); return; } else if (MdnsRecord.labelsAreSuffix(existingLabels, labels)) { diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java index 2c7b26bc93..c88ead09e5 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPointerRecord.java @@ -19,6 +19,7 @@ package com.android.server.connectivity.mdns; import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -60,7 +61,8 @@ public class MdnsPointerRecord extends MdnsRecord { } public boolean hasSubtype() { - return (name != null) && (name.length > 2) && name[1].equals(MdnsConstants.SUBTYPE_LABEL); + return (name != null) && (name.length > 2) && MdnsUtils.equalsIgnoreDnsCase(name[1], + MdnsConstants.SUBTYPE_LABEL); } public String getSubtype() { @@ -74,7 +76,7 @@ public class MdnsPointerRecord extends MdnsRecord { @Override public int hashCode() { - return (super.hashCode() * 31) + Arrays.hashCode(pointer); + return (super.hashCode() * 31) + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(pointer)); } @Override @@ -86,6 +88,7 @@ public class MdnsPointerRecord extends MdnsRecord { return false; } - return super.equals(other) && Arrays.equals(pointer, ((MdnsPointerRecord) other).pointer); + return super.equals(other) && MdnsUtils.equalsDnsLabelIgnoreDnsCase(pointer, + ((MdnsPointerRecord) other).pointer); } } \ No newline at end of file diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java index 669b323f84..ecf846ecb1 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java @@ -21,9 +21,9 @@ import android.os.Looper; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.CollectionUtils; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -113,7 +113,8 @@ public class MdnsProber extends MdnsPacketRepeater { */ private static boolean containsName(@NonNull List records, @NonNull String[] name) { - return CollectionUtils.any(records, r -> Arrays.equals(name, r.getName())); + return CollectionUtils.any(records, + r -> MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, r.getName())); } } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java index 19630e3227..28bd1b4d23 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecord.java @@ -24,6 +24,7 @@ import android.os.SystemClock; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -136,7 +137,7 @@ public abstract class MdnsRecord { } for (int i = 0; i < list1.length; ++i) { - if (!list1[i].equals(list2[i + offset])) { + if (!MdnsUtils.equalsIgnoreDnsCase(list1[i], list2[i + offset])) { return false; } } @@ -271,12 +272,13 @@ public abstract class MdnsRecord { MdnsRecord otherRecord = (MdnsRecord) other; - return Arrays.equals(name, otherRecord.name) && (type == otherRecord.type); + return MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, otherRecord.name) && (type + == otherRecord.type); } @Override public int hashCode() { - return Objects.hash(Arrays.hashCode(name), type); + return Objects.hash(Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(name)), type); } /** @@ -297,7 +299,7 @@ public abstract class MdnsRecord { public Key(int recordType, String[] recordName) { this.recordType = recordType; - this.recordName = recordName; + this.recordName = MdnsUtils.toDnsLabelsLowerCase(recordName); } @Override diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java index f756459623..13752791f5 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsRecordRepository.java @@ -30,6 +30,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.HexDump; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.net.Inet4Address; @@ -329,7 +330,8 @@ public class MdnsRecordRepository { private int getServiceByName(@NonNull String serviceName) { for (int i = 0; i < mServices.size(); i++) { final ServiceRegistration registration = mServices.valueAt(i); - if (serviceName.equals(registration.serviceInfo.getServiceName())) { + if (MdnsUtils.equalsIgnoreDnsCase(serviceName, + registration.serviceInfo.getServiceName())) { return mServices.keyAt(i); } } @@ -545,7 +547,9 @@ public class MdnsRecordRepository { must match the question qtype unless the qtype is "ANY" (255) or the rrtype is "CNAME" (5), and the record rrclass must match the question qclass unless the qclass is "ANY" (255) */ - if (!Arrays.equals(info.record.getName(), question.getName())) continue; + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(info.record.getName(), question.getName())) { + continue; + } hasFullyOwnedNameMatch |= !info.isSharedName; // The repository does not store CNAME records @@ -747,7 +751,10 @@ public class MdnsRecordRepository { // happens. In fact probing is only done for the service name in the SRV record. // This means only SRV and TXT records need to be checked. final RecordInfo srvRecord = registration.srvRecord; - if (!Arrays.equals(record.getName(), srvRecord.record.getName())) continue; + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(record.getName(), + srvRecord.record.getName())) { + continue; + } // As per RFC6762 9., it's fine if the "conflict" is an identical record with same // data. diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java index e0100f6a82..28aa640d96 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponse.java @@ -21,10 +21,10 @@ import android.annotation.Nullable; import android.net.Network; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; @@ -103,7 +103,7 @@ public class MdnsResponse { * pointer record is already present in the response with the same TTL. */ public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) { - if (!Arrays.equals(serviceName, pointerRecord.getPointer())) { + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceName, pointerRecord.getPointer())) { throw new IllegalArgumentException( "Pointer records for different service names cannot be added"); } @@ -301,13 +301,13 @@ public class MdnsResponse { boolean dropAddressRecords = false; for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) { - if (!Arrays.equals( + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase( this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) { dropAddressRecords = true; } } for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) { - if (!Arrays.equals( + if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase( this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) { dropAddressRecords = true; } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java index 129db7eefa..77b5c58d44 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java @@ -23,10 +23,10 @@ import android.os.SystemClock; import android.util.ArraySet; import com.android.server.connectivity.mdns.util.MdnsLogger; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.EOFException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -50,7 +50,7 @@ public class MdnsResponseDecoder { List responses, String[] pointer) { if (responses != null) { for (MdnsResponse response : responses) { - if (Arrays.equals(response.getServiceName(), pointer)) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(response.getServiceName(), pointer)) { return response; } } @@ -66,7 +66,8 @@ public class MdnsResponseDecoder { if (serviceRecord == null) { continue; } - if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(), + hostName)) { return response; } } @@ -164,11 +165,8 @@ public class MdnsResponseDecoder { for (MdnsRecord record : records) { if (record instanceof MdnsPointerRecord) { String[] name = record.getName(); - if ((serviceType == null) - || Arrays.equals(name, serviceType) - || ((name.length == (serviceType.length + 2)) - && name[1].equals(MdnsConstants.SUBTYPE_LABEL) - && MdnsRecord.labelsAreSuffix(serviceType, name))) { + if ((serviceType == null) || MdnsUtils.typeEqualsOrIsSubtype( + serviceType, name)) { MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record; // Group PTR records that refer to the same service instance name into a single // response. @@ -296,7 +294,7 @@ public class MdnsResponseDecoder { if (serviceRecord == null) { continue; } - if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) { + if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(), hostName)) { if (result == null) { result = new ArrayList<>(/* initialCapacity= */ responses.size()); } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java index ebd8b77baa..f851b35505 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceRecord.java @@ -19,6 +19,7 @@ package com.android.server.connectivity.mdns; import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.util.Arrays; @@ -142,7 +143,8 @@ public class MdnsServiceRecord extends MdnsRecord { @Override public int hashCode() { return (super.hashCode() * 31) - + Objects.hash(servicePriority, serviceWeight, Arrays.hashCode(serviceHost), + + Objects.hash(servicePriority, serviceWeight, + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(serviceHost)), servicePort); } @@ -159,7 +161,7 @@ public class MdnsServiceRecord extends MdnsRecord { return super.equals(other) && (servicePriority == otherRecord.servicePriority) && (serviceWeight == otherRecord.serviceWeight) - && Arrays.equals(serviceHost, otherRecord.serviceHost) + && MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceHost, otherRecord.serviceHost) && (servicePort == otherRecord.servicePort); } } diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java index 5cc789f7ce..63d1a504fe 100644 --- a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java +++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java @@ -21,6 +21,9 @@ import android.annotation.Nullable; import android.net.Network; import android.os.Handler; +import com.android.server.connectivity.mdns.MdnsConstants; +import com.android.server.connectivity.mdns.MdnsRecord; + import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; @@ -49,6 +52,17 @@ public class MdnsUtils { return new String(outChars); } + /** + * Convert the array of labels to DNS case-insensitive lowercase. + */ + public static String[] toDnsLabelsLowerCase(@NonNull String[] labels) { + final String[] outStrings = new String[labels.length]; + for (int i = 0; i < labels.length; ++i) { + outStrings[i] = toDnsLowerCase(labels[i]); + } + return outStrings; + } + /** * Compare two strings by DNS case-insensitive lowercase. */ @@ -62,6 +76,39 @@ public class MdnsUtils { return true; } + /** + * Compare two set of DNS labels by DNS case-insensitive lowercase. + */ + public static boolean equalsDnsLabelIgnoreDnsCase(@NonNull String[] a, @NonNull String[] b) { + if (a == b) { + return true; + } + int length = a.length; + if (b.length != length) { + return false; + } + for (int i = 0; i < length; i++) { + if (!equalsIgnoreDnsCase(a[i], b[i])) { + return false; + } + } + return true; + } + + /** + * Compare labels a equals b or a is suffix of b. + * + * @param a the type or subtype. + * @param b the base type + */ + public static boolean typeEqualsOrIsSubtype(@NonNull String[] a, + @NonNull String[] b) { + return MdnsUtils.equalsDnsLabelIgnoreDnsCase(a, b) + || ((b.length == (a.length + 2)) + && MdnsUtils.equalsIgnoreDnsCase(b[1], MdnsConstants.SUBTYPE_LABEL) + && MdnsRecord.labelsAreSuffix(a, b)); + } + private static char toDnsLowerCase(char a) { return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a; } diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt index b539fe0a83..d9acc61e45 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt @@ -51,6 +51,7 @@ private const val SERVICE_ID_1 = 1 private const val SERVICE_ID_2 = 2 private const val LONG_SERVICE_ID_1 = 3 private const val LONG_SERVICE_ID_2 = 4 +private const val CASE_INSENSITIVE_TEST_SERVICE_ID = 5 private const val TIMEOUT_MS = 10_000L private val TEST_ADDR = parseNumericAddress("2001:db8::123") private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */) @@ -78,6 +79,13 @@ private val ALL_NETWORKS_SERVICE = NsdServiceInfo("TestServiceName", "_advertise network = null } +private val ALL_NETWORKS_SERVICE_2 = + NsdServiceInfo("TESTSERVICENAME", "_ADVERTISERTEST._tcp").apply { + port = 12345 + hostAddresses = listOf(TEST_ADDR) + network = null + } + private val LONG_ALL_NETWORKS_SERVICE = NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply { port = 12345 @@ -228,6 +236,9 @@ class MdnsAdvertiserTest { postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE, null /* subtype */) } + postSync { advertiser.addService(CASE_INSENSITIVE_TEST_SERVICE_ID, ALL_NETWORKS_SERVICE_2, + null /* subtype */) } + // Callbacks for matching network and all networks both get the socket postSync { oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR)) @@ -249,6 +260,14 @@ class MdnsAdvertiserTest { network = LONG_ALL_NETWORKS_SERVICE.network } + val expectedCaseInsensitiveRenamed = NsdServiceInfo( + "${ALL_NETWORKS_SERVICE_2.serviceName} (3)", ALL_NETWORKS_SERVICE_2.serviceType + ).apply { + port = ALL_NETWORKS_SERVICE_2.port + hostAddresses = ALL_NETWORKS_SERVICE_2.hostAddresses + network = ALL_NETWORKS_SERVICE_2.network + } + val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java) verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)), eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any() @@ -261,6 +280,8 @@ class MdnsAdvertiserTest { argThat { it.matches(LONG_SERVICE_1) }, eq(null)) verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2), argThat { it.matches(expectedLongRenamed) }, eq(null)) + verify(mockInterfaceAdvertiser1).addService(eq(CASE_INSENSITIVE_TEST_SERVICE_ID), + argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null)) doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1) postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded( diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt index 5c9c294f16..a545373a98 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsPacketWriterTest.kt @@ -31,7 +31,7 @@ class MdnsPacketWriterTest { @Test fun testNameCompression() { val writer = MdnsPacketWriter(ByteArray(1000)) - writer.writeLabels(arrayOf("my", "first", "name")) + writer.writeLabels(arrayOf("my", "FIRST", "name")) writer.writeLabels(arrayOf("my", "second", "name")) writer.writeLabels(arrayOf("other", "first", "name")) writer.writeLabels(arrayOf("my", "second", "name")) @@ -41,7 +41,7 @@ class MdnsPacketWriterTest { InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123)) // Each label takes length + 1. So "first.name" offset = 3, "name" offset = 9 - val expected = "my".label() + "first".label() + "name".label() + 0x00.toByte() + + val expected = "my".label() + "FIRST".label() + "name".label() + 0x00.toByte() + // "my.second.name" offset = 15 "my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) + "other".label() + byteArrayOf(0xC0.toByte(), 3) + diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt index 2b5423b639..0a8d78ddc3 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt @@ -48,6 +48,7 @@ private const val SHORT_TIMEOUT_MS = 200L private val TEST_SERVICE_NAME_1 = arrayOf("testservice", "_nmt", "_tcp", "local") private val TEST_SERVICE_NAME_2 = arrayOf("testservice2", "_nmt", "_tcp", "local") +private val TEST_SERVICE_NAME_3 = arrayOf("Testservice", "_nmt", "_tcp", "local") @RunWith(DevSdkIgnoreRunner::class) @IgnoreUpTo(Build.VERSION_CODES.S_V2) @@ -128,6 +129,15 @@ class MdnsProberTest { assertProbesSent(probeInfo, expected) } + @Test + fun testCreateProberCaseInsensitive() { + val probeInfo = TestProbeInfo( + listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890), + makeServiceRecord(TEST_SERVICE_NAME_2, 37890), + makeServiceRecord(TEST_SERVICE_NAME_3, 37890))) + assertEquals(2, probeInfo.getPacket(0).questions.size) + } + @Test fun testProbeMultipleRecords() { val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer) diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt index 4a39b935f3..0033b5a1dc 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt @@ -43,6 +43,7 @@ import org.junit.runner.RunWith private const val TEST_SERVICE_ID_1 = 42 private const val TEST_SERVICE_ID_2 = 43 +private const val TEST_SERVICE_ID_3 = 44 private const val TEST_PORT = 12345 private const val TEST_SUBTYPE = "_subtype" private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local") @@ -63,6 +64,12 @@ private val TEST_SERVICE_2 = NsdServiceInfo().apply { port = TEST_PORT } +private val TEST_SERVICE_3 = NsdServiceInfo().apply { + serviceType = "_TESTSERVICE._tcp" + serviceName = "MyTESTSERVICE" + port = TEST_PORT +} + @RunWith(DevSdkIgnoreRunner::class) @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) class MdnsRecordRepositoryTest { @@ -124,6 +131,9 @@ class MdnsRecordRepositoryTest { assertFailsWith(NameConflictException::class) { repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */) } + assertFailsWith(NameConflictException::class) { + repository.addService(TEST_SERVICE_ID_3, TEST_SERVICE_3, null /* subtype */) + } } @Test @@ -364,6 +374,27 @@ class MdnsRecordRepositoryTest { assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123"))) } + @Test + fun testGetReplyCaseInsensitive() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1) + val questionsCaseInSensitive = + listOf(MdnsPointerRecord(arrayOf("_TESTSERVICE", "_TCP", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + // TTL and data is empty for a question + 0L /* ttlMillis */, + null /* pointer */)) + val queryCaseInsensitive = MdnsPacket(0 /* flags */, questionsCaseInSensitive, + listOf() /* answers */, listOf() /* authorityRecords */, + listOf() /* additionalRecords */) + val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353) + val replyCaseInsensitive = repository.getReply(queryCaseInsensitive, src) + assertNotNull(replyCaseInsensitive) + assertEquals(1, replyCaseInsensitive.answers.size) + assertEquals(7, replyCaseInsensitive.additionalAnswers.size) + } + @Test fun testGetReply() { doGetReplyTest(subtype = null) @@ -489,6 +520,34 @@ class MdnsRecordRepositoryTest { repository.getConflictingServices(packet)) } + @Test + fun testGetConflictingServicesCaseInsensitive() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port + 1, + TEST_HOSTNAME), + MdnsTextRecord( + arrayOf("MYOTHERTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */, + listOf(TextEntry.fromString("somedifferent=entry"))), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + assertEquals(setOf(TEST_SERVICE_ID_1, TEST_SERVICE_ID_2), + repository.getConflictingServices(packet)) + } + @Test fun testGetConflictingServices_IdenticalService() { val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) @@ -505,7 +564,7 @@ class MdnsRecordRepositoryTest { 0L /* receiptTimeMillis */, true /* cacheFlush */, otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */, TEST_SERVICE_1.port, - TEST_HOSTNAME), + arrayOf("ANDROID_000102030405060708090A0B0C0D0E0F", "local")), MdnsTextRecord( arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"), 0L /* receiptTimeMillis */, true /* cacheFlush */, @@ -517,6 +576,35 @@ class MdnsRecordRepositoryTest { // Above records are identical to the actual registrations: no conflict assertEquals(emptySet(), repository.getConflictingServices(packet)) } + + @Test + fun testGetConflictingServicesCaseInsensitive_IdenticalService() { + val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME) + repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */) + repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */) + + val otherTtlMillis = 1234L + val packet = MdnsPacket( + 0 /* flags */, + emptyList() /* questions */, + listOf( + MdnsServiceRecord( + arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */, + TEST_SERVICE_1.port, + TEST_HOSTNAME), + MdnsTextRecord( + arrayOf("MyOtherTestService", "_TESTSERVICE", "_tcp", "local"), + 0L /* receiptTimeMillis */, true /* cacheFlush */, + otherTtlMillis, emptyList()), + ) /* answers */, + emptyList() /* authorityRecords */, + emptyList() /* additionalRecords */) + + // Above records are identical to the actual registrations: no conflict + assertEquals(emptySet(), repository.getConflictingServices(packet)) + } } private fun MdnsRecordRepository.initWithService( diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt new file mode 100644 index 0000000000..8f819b7e89 --- /dev/null +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordTest.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity.mdns + +import android.os.Build +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) +class MdnsRecordTest { + + @Test + fun testPointerRecordHasSubType() { + val ptrRecord1 = MdnsPointerRecord( + arrayOf("_testtype", "_sub", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + val ptrRecord2 = MdnsPointerRecord( + arrayOf("_testtype", "_SUB", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + assertTrue(ptrRecord1.hasSubtype()) + assertTrue(ptrRecord2.hasSubtype()) + } + + @Test + fun testEqualsCaseInsensitive() { + val ptrRecord1 = MdnsPointerRecord( + arrayOf("_testtype", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testservice", "_testtype", "_tcp", "local") + ) + val ptrRecord2 = MdnsPointerRecord( + arrayOf("_testType", "_tcp", "local"), + 0L /* receiptTimeMillis */, + false /* cacheFlush */, + 4500000 /* ttlMillis */, + arrayOf("testsErvice", "_testtype", "_Tcp", "local") + ) + assertEquals(ptrRecord1, ptrRecord2) + assertEquals(ptrRecord1.hashCode(), ptrRecord2.hashCode()) + + val srvRecord1 = MdnsServiceRecord( + arrayOf("testservice", "_testtype", "_tcp", "local"), + 123 /* receiptTimeMillis */, + false /* cacheFlush */, + 2000 /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + 80 /* port */, + arrayOf("hostname") + ) + val srvRecord2 = MdnsServiceRecord( + arrayOf("Testservice", "_testtype", "_tcp", "local"), + 123 /* receiptTimeMillis */, + false /* cacheFlush */, + 2000 /* ttlMillis */, + 0 /* servicePriority */, + 0 /* serviceWeight */, + 80 /* port */, + arrayOf("Hostname") + ) + assertEquals(srvRecord1, srvRecord2) + assertEquals(srvRecord1.hashCode(), srvRecord2.hashCode()) + + val nsecRecord1 = MdnsNsecRecord( + arrayOf("hostname"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 2000L, /* ttlMillis */ + arrayOf("hostname"), + intArrayOf(1, 2, 3) /* types */ + ) + val nsecRecord2 = MdnsNsecRecord( + arrayOf("HOSTNAME"), + 0L /* receiptTimeMillis */, + true /* cacheFlush */, + 2000L, /* ttlMillis */ + arrayOf("HOSTNAME"), + intArrayOf(1, 2, 3) /* types */ + ) + assertEquals(nsecRecord1, nsecRecord2) + assertEquals(nsecRecord1.hashCode(), nsecRecord2.hashCode()) + } + + @Test + fun testLabelsAreSuffix() { + val labels1 = arrayOf("a", "b", "c") + val labels2 = arrayOf("B", "C") + val labels3 = arrayOf("b", "c") + val labels4 = arrayOf("b", "d") + assertTrue(MdnsRecord.labelsAreSuffix(labels2, labels1)) + assertTrue(MdnsRecord.labelsAreSuffix(labels3, labels1)) + assertFalse(MdnsRecord.labelsAreSuffix(labels4, labels1)) + } +} diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java index b0a1f183a2..e16c448de6 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseDecoderTests.java @@ -269,14 +269,9 @@ public class MdnsResponseDecoderTests { assertEquals("st=0", textStrings.get(6)); } - @Test - public void testDecodeIPv6AnswerPacket() throws IOException { - MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE); - assertNotNull(data6); - - responses = decode(decoder, data6); - assertEquals(1, responses.size()); - MdnsResponse response = responses.valueAt(0); + private void verifyResponse(ArraySet responseArraySet) { + assertEquals(1, responseArraySet.size()); + MdnsResponse response = responseArraySet.valueAt(0); assertTrue(response.isComplete()); MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord(); @@ -289,6 +284,22 @@ public class MdnsResponseDecoderTests { assertEquals(inet6Addr.getHostAddress(), "2000:3333::da6c:63ff:fe7c:7483"); } + @Test + public void testDecodeIPv6AnswerPacket() throws IOException { + MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE); + assertNotNull(data6); + verifyResponse(decode(decoder, data6)); + } + + @Test + public void testDecodeCaseInsensitiveMatch() throws IOException { + final String[] castServiceTypeUpperCase = + new String[] {"_GOOGLECAST", "_TCP", "LOCAL"}; + MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, castServiceTypeUpperCase); + assertNotNull(data6); + verifyResponse(decode(decoder, data6)); + } + @Test public void testIsComplete() { MdnsResponse response = new MdnsResponse(responses.valueAt(0)); diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java index 3f5e7a101c..dc0e64650f 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsResponseTests.java @@ -228,6 +228,12 @@ public class MdnsResponseTests { final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS); assertFalse(response.addPointerRecord(response.getPointerRecords().get(0))); + final String[] serviceName = new String[] { "MYSERVICE", "_TYPE", "_tcp", "local" }; + final String[] serviceType = new String[] { "_TYPE", "_tcp", "local" }; + MdnsPointerRecord pointerRecordCaseInsensitive = + new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */, + false /* cacheFlush */, TEST_TTL_MS, serviceName); + assertFalse(response.addPointerRecord(pointerRecordCaseInsensitive)); assertFalse(response.addInet6AddressRecord(response.getInet6AddressRecord())); assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord())); assertFalse(response.setServiceRecord(response.getServiceRecord())); @@ -270,4 +276,30 @@ public class MdnsResponseTests { // All records were replaced, not added assertEquals(ttlZeroResponse.getRecords().size(), response.getRecords().size()); } + + @Test + public void dropUnmatchedAddressRecords_caseInsensitive() { + + final String[] hostname = new String[] { "MyHostname" }; + final String[] upperCaseHostName = new String[] { "MYHOSTNAME" }; + final String[] serviceName = new String[] { "MyService", "_type", "_tcp", "local" }; + final String[] serviceType = new String[] { "_type", "_tcp", "local" }; + final MdnsResponse response = new MdnsResponse(/* now= */ 0, serviceName, INTERFACE_INDEX, + mNetwork); + response.addPointerRecord(new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */, + false /* cacheFlush */, TEST_TTL_MS, serviceName)); + response.setServiceRecord(new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL_MS, 0 /* servicePriority */, + 0 /* serviceWeight */, 0 /* servicePort */, hostname)); + response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */, + true /* cacheFlush */, TEST_TTL_MS, emptyList() /* entries */)); + response.addInet4AddressRecord(new MdnsInetAddressRecord( + upperCaseHostName , 0L /* receiptTimeMillis */, true /* cacheFlush */, + TEST_TTL_MS, parseNumericAddress("192.0.2.123"))); + response.addInet6AddressRecord(new MdnsInetAddressRecord( + upperCaseHostName, 0L /* receiptTimeMillis */, true /* cacheFlush */, + TEST_TTL_MS, parseNumericAddress("2001:db8::123"))); + + assertFalse(response.dropUnmatchedAddressRecords()); + } } \ No newline at end of file diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java index 4e69f473e0..42d296ba5c 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java @@ -1036,10 +1036,11 @@ public class MdnsServiceTypeClientTests { final String otherInstance = "instance2"; final String ipV4Address = "192.0.2.0"; final String ipV6Address = "2001:db8::"; + final String capitalizedRequestInstance = "Instance1"; final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() // Use different case in the options - .setResolveInstanceName("Instance1").build(); + .setResolveInstanceName(capitalizedRequestInstance).build(); client.startSendAndReceive(mockListenerOne, resolveOptions); client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions()); @@ -1067,8 +1068,9 @@ public class MdnsServiceTypeClientTests { Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork); // mockListenerOne gets notified for the requested instance - verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance)); - verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance)); + verify(mockListenerOne).onServiceNameDiscovered( + matchServiceName(capitalizedRequestInstance)); + verify(mockListenerOne).onServiceFound(matchServiceName(capitalizedRequestInstance)); // ...but does not get any callback for the other instance verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance)); @@ -1079,8 +1081,9 @@ public class MdnsServiceTypeClientTests { // mockListenerTwo gets notified for both though final InOrder inOrder = inOrder(mockListenerTwo); inOrder.verify(mockListenerTwo).onServiceNameDiscovered( - matchServiceName(requestedInstance)); - inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance)); + matchServiceName(capitalizedRequestInstance)); + inOrder.verify(mockListenerTwo).onServiceFound( + matchServiceName(capitalizedRequestInstance)); inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance)); inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance)); @@ -1179,8 +1182,7 @@ public class MdnsServiceTypeClientTests { final String ipV4Address = "192.0.2.0"; final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder() - // Use different case in the options - .setResolveInstanceName("Instance1").build(); + .setResolveInstanceName("instance1").build(); client.startSendAndReceive(mockListenerOne, resolveOptions); // Ensure the first task is executed so it schedules a future task diff --git a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt index 61c3a70921..f705bcb836 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt +++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt @@ -17,11 +17,14 @@ package com.android.server.connectivity.mdns.util import android.os.Build +import com.android.server.connectivity.mdns.util.MdnsUtils.equalsDnsLabelIgnoreDnsCase import com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase +import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLabelsLowerCase import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRunner +import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -49,6 +52,12 @@ class MdnsUtilsTest { "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<")) } + @Test + fun testToDnsLabelsLowerCase() { + assertArrayEquals(arrayOf("test", "tÉst", "ţést"), + toDnsLabelsLowerCase(arrayOf("TeSt", "TÉST", "ţést"))) + } + @Test fun testEqualsIgnoreDnsCase() { assertTrue(equalsIgnoreDnsCase("TEST", "Test")) @@ -72,4 +81,25 @@ class MdnsUtilsTest { assertEquals(truncateServiceName("测试abcde", 7), "测试a") assertEquals(truncateServiceName("测试abcde", 100), "测试abcde") } + + @Test + fun testEqualsLabelIgnoreDnsCase() { + assertTrue(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("Test"), arrayOf("test", "test"))) + assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "tést"))) + } + + @Test + fun testTypeEqualsOrIsSubtype() { + assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"), + arrayOf("_type", "_TCP", "local"))) + assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"), + arrayOf("a", "_SUB", "_type", "_TCP", "local"))) + assertFalse(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_sub", "_type", "_tcp", "local"), + arrayOf("_type", "_TCP", "local"))) + assertFalse(MdnsUtils.typeEqualsOrIsSubtype( + arrayOf("a", "_other", "_type", "_tcp", "local"), + arrayOf("a", "_SUB", "_type", "_TCP", "local"))) + } }