Use case-insensitive matching in discovery/advertising
mDNS is supposed to be case-insensitive (like DNS). Both advertising and discovery logic should use case-insensitive matching instead of case-sensitive matching. The case sensitive matching can be found by grepping the String.equals() and Arrays.equals() check across the whole code base. Each occurrence is analyzed carefully to list up all necessary fixes. Bug: 272194544 Test: atest FrameworksNetTests Change-Id: I7c10878129663549c9171c1420b6f399930df2cb
This commit is contained in:
@@ -253,8 +253,9 @@ public class MdnsAdvertiser {
|
|||||||
int getConflictingService(@NonNull NsdServiceInfo info) {
|
int getConflictingService(@NonNull NsdServiceInfo info) {
|
||||||
for (int i = 0; i < mPendingRegistrations.size(); i++) {
|
for (int i = 0; i < mPendingRegistrations.size(); i++) {
|
||||||
final NsdServiceInfo other = mPendingRegistrations.valueAt(i).getServiceInfo();
|
final NsdServiceInfo other = mPendingRegistrations.valueAt(i).getServiceInfo();
|
||||||
if (info.getServiceName().equals(other.getServiceName())
|
if (MdnsUtils.equalsIgnoreDnsCase(info.getServiceName(), other.getServiceName())
|
||||||
&& info.getServiceType().equals(other.getServiceType())) {
|
&& MdnsUtils.equalsIgnoreDnsCase(info.getServiceType(),
|
||||||
|
other.getServiceType())) {
|
||||||
return mPendingRegistrations.keyAt(i);
|
return mPendingRegistrations.keyAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import android.util.Pair;
|
|||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.net.module.util.SharedLog;
|
import com.android.net.module.util.SharedLog;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -56,21 +57,26 @@ public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback {
|
|||||||
|
|
||||||
public void put(@NonNull String serviceType, @Nullable Network network,
|
public void put(@NonNull String serviceType, @Nullable Network network,
|
||||||
@NonNull MdnsServiceTypeClient client) {
|
@NonNull MdnsServiceTypeClient client) {
|
||||||
final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
|
final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
|
||||||
|
final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType,
|
||||||
|
network);
|
||||||
clients.put(perNetworkServiceType, client);
|
clients.put(perNetworkServiceType, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) {
|
public MdnsServiceTypeClient get(@NonNull String serviceType, @Nullable Network network) {
|
||||||
final Pair<String, Network> perNetworkServiceType = new Pair<>(serviceType, network);
|
final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
|
||||||
|
final Pair<String, Network> perNetworkServiceType = new Pair<>(dnsLowerServiceType,
|
||||||
|
network);
|
||||||
return clients.getOrDefault(perNetworkServiceType, null);
|
return clients.getOrDefault(perNetworkServiceType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MdnsServiceTypeClient> getByServiceType(@NonNull String serviceType) {
|
public List<MdnsServiceTypeClient> getByServiceType(@NonNull String serviceType) {
|
||||||
|
final String dnsLowerServiceType = MdnsUtils.toDnsLowerCase(serviceType);
|
||||||
final List<MdnsServiceTypeClient> list = new ArrayList<>();
|
final List<MdnsServiceTypeClient> list = new ArrayList<>();
|
||||||
for (int i = 0; i < clients.size(); i++) {
|
for (int i = 0; i < clients.size(); i++) {
|
||||||
final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
|
final Pair<String, Network> perNetworkServiceType = clients.keyAt(i);
|
||||||
if (serviceType.equals(perNetworkServiceType.first)) {
|
if (dnsLowerServiceType.equals(perNetworkServiceType.first)) {
|
||||||
list.add(clients.valueAt(i));
|
list.add(clients.valueAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.net.DnsResolver;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.net.module.util.CollectionUtils;
|
import com.android.net.module.util.CollectionUtils;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -152,7 +153,8 @@ public class MdnsNsecRecord extends MdnsRecord {
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(),
|
return Objects.hash(super.hashCode(),
|
||||||
Arrays.hashCode(mNextDomain), Arrays.hashCode(mTypes));
|
Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(mNextDomain)),
|
||||||
|
Arrays.hashCode(mTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,7 +167,8 @@ public class MdnsNsecRecord extends MdnsRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return super.equals(other)
|
return super.equals(other)
|
||||||
&& Arrays.equals(mNextDomain, ((MdnsNsecRecord) other).mNextDomain)
|
&& MdnsUtils.equalsDnsLabelIgnoreDnsCase(mNextDomain,
|
||||||
|
((MdnsNsecRecord) other).mNextDomain)
|
||||||
&& Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes);
|
&& Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
package com.android.server.connectivity.mdns;
|
package com.android.server.connectivity.mdns;
|
||||||
|
|
||||||
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
|
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ public class MdnsPacketWriter {
|
|||||||
int existingOffset = entry.getKey();
|
int existingOffset = entry.getKey();
|
||||||
String[] existingLabels = entry.getValue();
|
String[] existingLabels = entry.getValue();
|
||||||
|
|
||||||
if (Arrays.equals(existingLabels, labels)) {
|
if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(existingLabels, labels)) {
|
||||||
writePointer(existingOffset);
|
writePointer(existingOffset);
|
||||||
return;
|
return;
|
||||||
} else if (MdnsRecord.labelsAreSuffix(existingLabels, labels)) {
|
} else if (MdnsRecord.labelsAreSuffix(existingLabels, labels)) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.server.connectivity.mdns;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -60,7 +61,8 @@ public class MdnsPointerRecord extends MdnsRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSubtype() {
|
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() {
|
public String getSubtype() {
|
||||||
@@ -74,7 +76,7 @@ public class MdnsPointerRecord extends MdnsRecord {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (super.hashCode() * 31) + Arrays.hashCode(pointer);
|
return (super.hashCode() * 31) + Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(pointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,6 +88,7 @@ public class MdnsPointerRecord extends MdnsRecord {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.equals(other) && Arrays.equals(pointer, ((MdnsPointerRecord) other).pointer);
|
return super.equals(other) && MdnsUtils.equalsDnsLabelIgnoreDnsCase(pointer,
|
||||||
|
((MdnsPointerRecord) other).pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,9 +21,9 @@ import android.os.Looper;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.net.module.util.CollectionUtils;
|
import com.android.net.module.util.CollectionUtils;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -113,7 +113,8 @@ public class MdnsProber extends MdnsPacketRepeater<MdnsProber.ProbingInfo> {
|
|||||||
*/
|
*/
|
||||||
private static boolean containsName(@NonNull List<MdnsRecord> records,
|
private static boolean containsName(@NonNull List<MdnsRecord> records,
|
||||||
@NonNull String[] name) {
|
@NonNull String[] name) {
|
||||||
return CollectionUtils.any(records, r -> Arrays.equals(name, r.getName()));
|
return CollectionUtils.any(records,
|
||||||
|
r -> MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, r.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.os.SystemClock;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -136,7 +137,7 @@ public abstract class MdnsRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < list1.length; ++i) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,12 +272,13 @@ public abstract class MdnsRecord {
|
|||||||
|
|
||||||
MdnsRecord otherRecord = (MdnsRecord) other;
|
MdnsRecord otherRecord = (MdnsRecord) other;
|
||||||
|
|
||||||
return Arrays.equals(name, otherRecord.name) && (type == otherRecord.type);
|
return MdnsUtils.equalsDnsLabelIgnoreDnsCase(name, otherRecord.name) && (type
|
||||||
|
== otherRecord.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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) {
|
public Key(int recordType, String[] recordName) {
|
||||||
this.recordType = recordType;
|
this.recordType = recordType;
|
||||||
this.recordName = recordName;
|
this.recordName = MdnsUtils.toDnsLabelsLowerCase(recordName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import android.util.SparseArray;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.net.module.util.CollectionUtils;
|
import com.android.net.module.util.CollectionUtils;
|
||||||
import com.android.net.module.util.HexDump;
|
import com.android.net.module.util.HexDump;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
@@ -329,7 +330,8 @@ public class MdnsRecordRepository {
|
|||||||
private int getServiceByName(@NonNull String serviceName) {
|
private int getServiceByName(@NonNull String serviceName) {
|
||||||
for (int i = 0; i < mServices.size(); i++) {
|
for (int i = 0; i < mServices.size(); i++) {
|
||||||
final ServiceRegistration registration = mServices.valueAt(i);
|
final ServiceRegistration registration = mServices.valueAt(i);
|
||||||
if (serviceName.equals(registration.serviceInfo.getServiceName())) {
|
if (MdnsUtils.equalsIgnoreDnsCase(serviceName,
|
||||||
|
registration.serviceInfo.getServiceName())) {
|
||||||
return mServices.keyAt(i);
|
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
|
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
|
"CNAME" (5), and the record rrclass must match the question qclass unless the
|
||||||
qclass is "ANY" (255) */
|
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;
|
hasFullyOwnedNameMatch |= !info.isSharedName;
|
||||||
|
|
||||||
// The repository does not store CNAME records
|
// 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.
|
// 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.
|
// This means only SRV and TXT records need to be checked.
|
||||||
final RecordInfo<MdnsServiceRecord> srvRecord = registration.srvRecord;
|
final RecordInfo<MdnsServiceRecord> 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
|
// As per RFC6762 9., it's fine if the "conflict" is an identical record with same
|
||||||
// data.
|
// data.
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ import android.annotation.Nullable;
|
|||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -103,7 +103,7 @@ public class MdnsResponse {
|
|||||||
* pointer record is already present in the response with the same TTL.
|
* pointer record is already present in the response with the same TTL.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) {
|
public synchronized boolean addPointerRecord(MdnsPointerRecord pointerRecord) {
|
||||||
if (!Arrays.equals(serviceName, pointerRecord.getPointer())) {
|
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceName, pointerRecord.getPointer())) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Pointer records for different service names cannot be added");
|
"Pointer records for different service names cannot be added");
|
||||||
}
|
}
|
||||||
@@ -301,13 +301,13 @@ public class MdnsResponse {
|
|||||||
boolean dropAddressRecords = false;
|
boolean dropAddressRecords = false;
|
||||||
|
|
||||||
for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) {
|
for (MdnsInetAddressRecord inetAddressRecord : getInet4AddressRecords()) {
|
||||||
if (!Arrays.equals(
|
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(
|
||||||
this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
|
this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
|
||||||
dropAddressRecords = true;
|
dropAddressRecords = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) {
|
for (MdnsInetAddressRecord inetAddressRecord : getInet6AddressRecords()) {
|
||||||
if (!Arrays.equals(
|
if (!MdnsUtils.equalsDnsLabelIgnoreDnsCase(
|
||||||
this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
|
this.serviceRecord.getServiceHost(), inetAddressRecord.getName())) {
|
||||||
dropAddressRecords = true;
|
dropAddressRecords = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ import android.os.SystemClock;
|
|||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import com.android.server.connectivity.mdns.util.MdnsLogger;
|
import com.android.server.connectivity.mdns.util.MdnsLogger;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ public class MdnsResponseDecoder {
|
|||||||
List<MdnsResponse> responses, String[] pointer) {
|
List<MdnsResponse> responses, String[] pointer) {
|
||||||
if (responses != null) {
|
if (responses != null) {
|
||||||
for (MdnsResponse response : responses) {
|
for (MdnsResponse response : responses) {
|
||||||
if (Arrays.equals(response.getServiceName(), pointer)) {
|
if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(response.getServiceName(), pointer)) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,8 @@ public class MdnsResponseDecoder {
|
|||||||
if (serviceRecord == null) {
|
if (serviceRecord == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) {
|
if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(),
|
||||||
|
hostName)) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,11 +165,8 @@ public class MdnsResponseDecoder {
|
|||||||
for (MdnsRecord record : records) {
|
for (MdnsRecord record : records) {
|
||||||
if (record instanceof MdnsPointerRecord) {
|
if (record instanceof MdnsPointerRecord) {
|
||||||
String[] name = record.getName();
|
String[] name = record.getName();
|
||||||
if ((serviceType == null)
|
if ((serviceType == null) || MdnsUtils.typeEqualsOrIsSubtype(
|
||||||
|| Arrays.equals(name, serviceType)
|
serviceType, name)) {
|
||||||
|| ((name.length == (serviceType.length + 2))
|
|
||||||
&& name[1].equals(MdnsConstants.SUBTYPE_LABEL)
|
|
||||||
&& MdnsRecord.labelsAreSuffix(serviceType, name))) {
|
|
||||||
MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record;
|
MdnsPointerRecord pointerRecord = (MdnsPointerRecord) record;
|
||||||
// Group PTR records that refer to the same service instance name into a single
|
// Group PTR records that refer to the same service instance name into a single
|
||||||
// response.
|
// response.
|
||||||
@@ -296,7 +294,7 @@ public class MdnsResponseDecoder {
|
|||||||
if (serviceRecord == null) {
|
if (serviceRecord == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Arrays.equals(serviceRecord.getServiceHost(), hostName)) {
|
if (MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceRecord.getServiceHost(), hostName)) {
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = new ArrayList<>(/* initialCapacity= */ responses.size());
|
result = new ArrayList<>(/* initialCapacity= */ responses.size());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.server.connectivity.mdns;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.connectivity.mdns.util.MdnsUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -142,7 +143,8 @@ public class MdnsServiceRecord extends MdnsRecord {
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (super.hashCode() * 31)
|
return (super.hashCode() * 31)
|
||||||
+ Objects.hash(servicePriority, serviceWeight, Arrays.hashCode(serviceHost),
|
+ Objects.hash(servicePriority, serviceWeight,
|
||||||
|
Arrays.hashCode(MdnsUtils.toDnsLabelsLowerCase(serviceHost)),
|
||||||
servicePort);
|
servicePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +161,7 @@ public class MdnsServiceRecord extends MdnsRecord {
|
|||||||
return super.equals(other)
|
return super.equals(other)
|
||||||
&& (servicePriority == otherRecord.servicePriority)
|
&& (servicePriority == otherRecord.servicePriority)
|
||||||
&& (serviceWeight == otherRecord.serviceWeight)
|
&& (serviceWeight == otherRecord.serviceWeight)
|
||||||
&& Arrays.equals(serviceHost, otherRecord.serviceHost)
|
&& MdnsUtils.equalsDnsLabelIgnoreDnsCase(serviceHost, otherRecord.serviceHost)
|
||||||
&& (servicePort == otherRecord.servicePort);
|
&& (servicePort == otherRecord.servicePort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import android.annotation.Nullable;
|
|||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.os.Handler;
|
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.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@@ -49,6 +52,17 @@ public class MdnsUtils {
|
|||||||
return new String(outChars);
|
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.
|
* Compare two strings by DNS case-insensitive lowercase.
|
||||||
*/
|
*/
|
||||||
@@ -62,6 +76,39 @@ public class MdnsUtils {
|
|||||||
return true;
|
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) {
|
private static char toDnsLowerCase(char a) {
|
||||||
return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a;
|
return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ private const val SERVICE_ID_1 = 1
|
|||||||
private const val SERVICE_ID_2 = 2
|
private const val SERVICE_ID_2 = 2
|
||||||
private const val LONG_SERVICE_ID_1 = 3
|
private const val LONG_SERVICE_ID_1 = 3
|
||||||
private const val LONG_SERVICE_ID_2 = 4
|
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 const val TIMEOUT_MS = 10_000L
|
||||||
private val TEST_ADDR = parseNumericAddress("2001:db8::123")
|
private val TEST_ADDR = parseNumericAddress("2001:db8::123")
|
||||||
private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */)
|
private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */)
|
||||||
@@ -78,6 +79,13 @@ private val ALL_NETWORKS_SERVICE = NsdServiceInfo("TestServiceName", "_advertise
|
|||||||
network = null
|
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 =
|
private val LONG_ALL_NETWORKS_SERVICE =
|
||||||
NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply {
|
NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply {
|
||||||
port = 12345
|
port = 12345
|
||||||
@@ -228,6 +236,9 @@ class MdnsAdvertiserTest {
|
|||||||
postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE,
|
postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE,
|
||||||
null /* subtype */) }
|
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
|
// Callbacks for matching network and all networks both get the socket
|
||||||
postSync {
|
postSync {
|
||||||
oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR))
|
oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR))
|
||||||
@@ -249,6 +260,14 @@ class MdnsAdvertiserTest {
|
|||||||
network = LONG_ALL_NETWORKS_SERVICE.network
|
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)
|
val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
|
||||||
verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
|
verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
|
||||||
eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any()
|
eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any()
|
||||||
@@ -261,6 +280,8 @@ class MdnsAdvertiserTest {
|
|||||||
argThat { it.matches(LONG_SERVICE_1) }, eq(null))
|
argThat { it.matches(LONG_SERVICE_1) }, eq(null))
|
||||||
verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2),
|
verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2),
|
||||||
argThat { it.matches(expectedLongRenamed) }, eq(null))
|
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)
|
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
|
||||||
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
|
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class MdnsPacketWriterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testNameCompression() {
|
fun testNameCompression() {
|
||||||
val writer = MdnsPacketWriter(ByteArray(1000))
|
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("my", "second", "name"))
|
||||||
writer.writeLabels(arrayOf("other", "first", "name"))
|
writer.writeLabels(arrayOf("other", "first", "name"))
|
||||||
writer.writeLabels(arrayOf("my", "second", "name"))
|
writer.writeLabels(arrayOf("my", "second", "name"))
|
||||||
@@ -41,7 +41,7 @@ class MdnsPacketWriterTest {
|
|||||||
InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123))
|
InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123))
|
||||||
|
|
||||||
// Each label takes length + 1. So "first.name" offset = 3, "name" offset = 9
|
// 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.second.name" offset = 15
|
||||||
"my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) +
|
"my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) +
|
||||||
"other".label() + byteArrayOf(0xC0.toByte(), 3) +
|
"other".label() + byteArrayOf(0xC0.toByte(), 3) +
|
||||||
|
|||||||
@@ -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_1 = arrayOf("testservice", "_nmt", "_tcp", "local")
|
||||||
private val TEST_SERVICE_NAME_2 = arrayOf("testservice2", "_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)
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||||
@@ -128,6 +129,15 @@ class MdnsProberTest {
|
|||||||
assertProbesSent(probeInfo, expected)
|
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
|
@Test
|
||||||
fun testProbeMultipleRecords() {
|
fun testProbeMultipleRecords() {
|
||||||
val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
|
val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.junit.runner.RunWith
|
|||||||
|
|
||||||
private const val TEST_SERVICE_ID_1 = 42
|
private const val TEST_SERVICE_ID_1 = 42
|
||||||
private const val TEST_SERVICE_ID_2 = 43
|
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_PORT = 12345
|
||||||
private const val TEST_SUBTYPE = "_subtype"
|
private const val TEST_SUBTYPE = "_subtype"
|
||||||
private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
|
private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
|
||||||
@@ -63,6 +64,12 @@ private val TEST_SERVICE_2 = NsdServiceInfo().apply {
|
|||||||
port = TEST_PORT
|
port = TEST_PORT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val TEST_SERVICE_3 = NsdServiceInfo().apply {
|
||||||
|
serviceType = "_TESTSERVICE._tcp"
|
||||||
|
serviceName = "MyTESTSERVICE"
|
||||||
|
port = TEST_PORT
|
||||||
|
}
|
||||||
|
|
||||||
@RunWith(DevSdkIgnoreRunner::class)
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||||
class MdnsRecordRepositoryTest {
|
class MdnsRecordRepositoryTest {
|
||||||
@@ -124,6 +131,9 @@ class MdnsRecordRepositoryTest {
|
|||||||
assertFailsWith(NameConflictException::class) {
|
assertFailsWith(NameConflictException::class) {
|
||||||
repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */)
|
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
|
@Test
|
||||||
@@ -364,6 +374,27 @@ class MdnsRecordRepositoryTest {
|
|||||||
assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123")))
|
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
|
@Test
|
||||||
fun testGetReply() {
|
fun testGetReply() {
|
||||||
doGetReplyTest(subtype = null)
|
doGetReplyTest(subtype = null)
|
||||||
@@ -489,6 +520,34 @@ class MdnsRecordRepositoryTest {
|
|||||||
repository.getConflictingServices(packet))
|
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
|
@Test
|
||||||
fun testGetConflictingServices_IdenticalService() {
|
fun testGetConflictingServices_IdenticalService() {
|
||||||
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
|
||||||
@@ -505,7 +564,7 @@ class MdnsRecordRepositoryTest {
|
|||||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||||
otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
|
otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
|
||||||
TEST_SERVICE_1.port,
|
TEST_SERVICE_1.port,
|
||||||
TEST_HOSTNAME),
|
arrayOf("ANDROID_000102030405060708090A0B0C0D0E0F", "local")),
|
||||||
MdnsTextRecord(
|
MdnsTextRecord(
|
||||||
arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"),
|
arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"),
|
||||||
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
0L /* receiptTimeMillis */, true /* cacheFlush */,
|
||||||
@@ -517,6 +576,35 @@ class MdnsRecordRepositoryTest {
|
|||||||
// Above records are identical to the actual registrations: no conflict
|
// Above records are identical to the actual registrations: no conflict
|
||||||
assertEquals(emptySet(), repository.getConflictingServices(packet))
|
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(
|
private fun MdnsRecordRepository.initWithService(
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -269,14 +269,9 @@ public class MdnsResponseDecoderTests {
|
|||||||
assertEquals("st=0", textStrings.get(6));
|
assertEquals("st=0", textStrings.get(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void verifyResponse(ArraySet<MdnsResponse> responseArraySet) {
|
||||||
public void testDecodeIPv6AnswerPacket() throws IOException {
|
assertEquals(1, responseArraySet.size());
|
||||||
MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
|
MdnsResponse response = responseArraySet.valueAt(0);
|
||||||
assertNotNull(data6);
|
|
||||||
|
|
||||||
responses = decode(decoder, data6);
|
|
||||||
assertEquals(1, responses.size());
|
|
||||||
MdnsResponse response = responses.valueAt(0);
|
|
||||||
assertTrue(response.isComplete());
|
assertTrue(response.isComplete());
|
||||||
|
|
||||||
MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord();
|
MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord();
|
||||||
@@ -289,6 +284,22 @@ public class MdnsResponseDecoderTests {
|
|||||||
assertEquals(inet6Addr.getHostAddress(), "2000:3333::da6c:63ff:fe7c:7483");
|
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
|
@Test
|
||||||
public void testIsComplete() {
|
public void testIsComplete() {
|
||||||
MdnsResponse response = new MdnsResponse(responses.valueAt(0));
|
MdnsResponse response = new MdnsResponse(responses.valueAt(0));
|
||||||
|
|||||||
@@ -228,6 +228,12 @@ public class MdnsResponseTests {
|
|||||||
final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS);
|
final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS);
|
||||||
|
|
||||||
assertFalse(response.addPointerRecord(response.getPointerRecords().get(0)));
|
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.addInet6AddressRecord(response.getInet6AddressRecord()));
|
||||||
assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord()));
|
assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord()));
|
||||||
assertFalse(response.setServiceRecord(response.getServiceRecord()));
|
assertFalse(response.setServiceRecord(response.getServiceRecord()));
|
||||||
@@ -270,4 +276,30 @@ public class MdnsResponseTests {
|
|||||||
// All records were replaced, not added
|
// All records were replaced, not added
|
||||||
assertEquals(ttlZeroResponse.getRecords().size(), response.getRecords().size());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1006,10 +1006,11 @@ public class MdnsServiceTypeClientTests {
|
|||||||
final String otherInstance = "instance2";
|
final String otherInstance = "instance2";
|
||||||
final String ipV4Address = "192.0.2.0";
|
final String ipV4Address = "192.0.2.0";
|
||||||
final String ipV6Address = "2001:db8::";
|
final String ipV6Address = "2001:db8::";
|
||||||
|
final String capitalizedRequestInstance = "Instance1";
|
||||||
|
|
||||||
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
|
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
|
||||||
// Use different case in the options
|
// Use different case in the options
|
||||||
.setResolveInstanceName("Instance1").build();
|
.setResolveInstanceName(capitalizedRequestInstance).build();
|
||||||
|
|
||||||
client.startSendAndReceive(mockListenerOne, resolveOptions);
|
client.startSendAndReceive(mockListenerOne, resolveOptions);
|
||||||
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
|
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
|
||||||
@@ -1037,8 +1038,9 @@ public class MdnsServiceTypeClientTests {
|
|||||||
Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
|
Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
|
||||||
|
|
||||||
// mockListenerOne gets notified for the requested instance
|
// mockListenerOne gets notified for the requested instance
|
||||||
verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance));
|
verify(mockListenerOne).onServiceNameDiscovered(
|
||||||
verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
|
matchServiceName(capitalizedRequestInstance));
|
||||||
|
verify(mockListenerOne).onServiceFound(matchServiceName(capitalizedRequestInstance));
|
||||||
|
|
||||||
// ...but does not get any callback for the other instance
|
// ...but does not get any callback for the other instance
|
||||||
verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
|
verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
|
||||||
@@ -1049,8 +1051,9 @@ public class MdnsServiceTypeClientTests {
|
|||||||
// mockListenerTwo gets notified for both though
|
// mockListenerTwo gets notified for both though
|
||||||
final InOrder inOrder = inOrder(mockListenerTwo);
|
final InOrder inOrder = inOrder(mockListenerTwo);
|
||||||
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
|
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
|
||||||
matchServiceName(requestedInstance));
|
matchServiceName(capitalizedRequestInstance));
|
||||||
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
|
inOrder.verify(mockListenerTwo).onServiceFound(
|
||||||
|
matchServiceName(capitalizedRequestInstance));
|
||||||
|
|
||||||
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
|
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
|
||||||
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
|
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
|
||||||
@@ -1149,8 +1152,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
final String ipV4Address = "192.0.2.0";
|
final String ipV4Address = "192.0.2.0";
|
||||||
|
|
||||||
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
|
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
|
||||||
// Use different case in the options
|
.setResolveInstanceName("instance1").build();
|
||||||
.setResolveInstanceName("Instance1").build();
|
|
||||||
|
|
||||||
client.startSendAndReceive(mockListenerOne, resolveOptions);
|
client.startSendAndReceive(mockListenerOne, resolveOptions);
|
||||||
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
|
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
|
||||||
|
|||||||
@@ -17,11 +17,14 @@
|
|||||||
package com.android.server.connectivity.mdns.util
|
package com.android.server.connectivity.mdns.util
|
||||||
|
|
||||||
import android.os.Build
|
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.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.toDnsLowerCase
|
||||||
import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
|
import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
|
||||||
import com.android.testutils.DevSdkIgnoreRule
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
import com.android.testutils.DevSdkIgnoreRunner
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
@@ -49,6 +52,12 @@ class MdnsUtilsTest {
|
|||||||
"\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<"))
|
"\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToDnsLabelsLowerCase() {
|
||||||
|
assertArrayEquals(arrayOf("test", "tÉst", "ţést"),
|
||||||
|
toDnsLabelsLowerCase(arrayOf("TeSt", "TÉST", "ţést")))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEqualsIgnoreDnsCase() {
|
fun testEqualsIgnoreDnsCase() {
|
||||||
assertTrue(equalsIgnoreDnsCase("TEST", "Test"))
|
assertTrue(equalsIgnoreDnsCase("TEST", "Test"))
|
||||||
@@ -72,4 +81,25 @@ class MdnsUtilsTest {
|
|||||||
assertEquals(truncateServiceName("测试abcde", 7), "测试a")
|
assertEquals(truncateServiceName("测试abcde", 7), "测试a")
|
||||||
assertEquals(truncateServiceName("测试abcde", 100), "测试abcde")
|
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")))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user