Merge "Use case-insensitive matching in discovery/advertising"
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1036,10 +1036,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());
|
||||||
@@ -1067,8 +1068,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));
|
||||||
@@ -1079,8 +1081,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));
|
||||||
@@ -1179,8 +1182,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);
|
||||||
// Ensure the first task is executed so it schedules a future task
|
// Ensure the first task is executed so it schedules a future task
|
||||||
|
|||||||
@@ -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