Merge "Only send resolve callbacks for subscribed service"

This commit is contained in:
Treehugger Robot
2023-04-17 13:16:15 +00:00
committed by Gerrit Code Review
2 changed files with 79 additions and 0 deletions

View File

@@ -174,6 +174,7 @@ public class MdnsServiceTypeClient {
this.searchOptions = searchOptions; this.searchOptions = searchOptions;
if (listeners.put(listener, searchOptions) == null) { if (listeners.put(listener, searchOptions) == null) {
for (MdnsResponse existingResponse : instanceNameToResponse.values()) { for (MdnsResponse existingResponse : instanceNameToResponse.values()) {
if (!responseMatchesOptions(existingResponse, searchOptions)) continue;
final MdnsServiceInfo info = final MdnsServiceInfo info =
buildMdnsServiceInfoFromResponse(existingResponse, serviceTypeLabels); buildMdnsServiceInfoFromResponse(existingResponse, serviceTypeLabels);
listener.onServiceNameDiscovered(info); listener.onServiceNameDiscovered(info);
@@ -199,6 +200,13 @@ public class MdnsServiceTypeClient {
} }
} }
private boolean responseMatchesOptions(@NonNull MdnsResponse response,
@NonNull MdnsSearchOptions options) {
if (options.getResolveInstanceName() == null) return true;
// DNS is case-insensitive, so ignore case in the comparison
return options.getResolveInstanceName().equalsIgnoreCase(response.getServiceInstanceName());
}
/** /**
* Unregisters {@code listener} from receiving discovery event of mDNS service instances. * Unregisters {@code listener} from receiving discovery event of mDNS service instances.
* *
@@ -274,6 +282,7 @@ public class MdnsServiceTypeClient {
buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); buildMdnsServiceInfoFromResponse(response, serviceTypeLabels);
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
if (!responseMatchesOptions(response, listeners.valueAt(i))) continue;
final MdnsServiceBrowserListener listener = listeners.keyAt(i); final MdnsServiceBrowserListener listener = listeners.keyAt(i);
if (newServiceFound) { if (newServiceFound) {
listener.onServiceNameDiscovered(serviceInfo); listener.onServiceNameDiscovered(serviceInfo);
@@ -295,6 +304,7 @@ public class MdnsServiceTypeClient {
return; return;
} }
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
if (!responseMatchesOptions(response, listeners.valueAt(i))) continue;
final MdnsServiceBrowserListener listener = listeners.keyAt(i); final MdnsServiceBrowserListener listener = listeners.keyAt(i);
final MdnsServiceInfo serviceInfo = final MdnsServiceInfo serviceInfo =
buildMdnsServiceInfoFromResponse(response, serviceTypeLabels); buildMdnsServiceInfoFromResponse(response, serviceTypeLabels);
@@ -512,6 +522,10 @@ public class MdnsServiceTypeClient {
== 0) { == 0) {
iter.remove(); iter.remove();
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
if (!responseMatchesOptions(existingResponse,
listeners.valueAt(i))) {
continue;
}
final MdnsServiceBrowserListener listener = listeners.keyAt(i); final MdnsServiceBrowserListener listener = listeners.keyAt(i);
String serviceInstanceName = String serviceInstanceName =
existingResponse.getServiceInstanceName(); existingResponse.getServiceInstanceName();

View File

@@ -992,6 +992,71 @@ public class MdnsServiceTypeClientTests {
mockNetwork); mockNetwork);
} }
@Test
public void testProcessResponse_ResolveExcludesOtherServices() {
client = new MdnsServiceTypeClient(
SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork);
final String requestedInstance = "instance1";
final String otherInstance = "instance2";
final String ipV4Address = "192.0.2.0";
final String ipV6Address = "2001:db8::";
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
// Use different case in the options
.setResolveInstanceName("Instance1").build();
client.startSendAndReceive(mockListenerOne, resolveOptions);
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
// Complete response from instanceName
client.processResponse(createResponse(
requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap() /* textAttributes */, TEST_TTL),
INTERFACE_INDEX, mockNetwork);
// Complete response from otherInstanceName
client.processResponse(createResponse(
otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap() /* textAttributes */, TEST_TTL),
INTERFACE_INDEX, mockNetwork);
// Address update from otherInstanceName
client.processResponse(createResponse(
otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork);
// Goodbye from otherInstanceName
client.processResponse(createResponse(
otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
// mockListenerOne gets notified for the requested instance
verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance));
verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
// ...but does not get any callback for the other instance
verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceUpdated(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance));
// mockListenerTwo gets notified for both though
final InOrder inOrder = inOrder(mockListenerTwo);
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
matchServiceName(requestedInstance));
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
inOrder.verify(mockListenerTwo).onServiceUpdated(matchServiceName(otherInstance));
inOrder.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance));
}
private static MdnsServiceInfo matchServiceName(String name) {
return argThat(info -> info.getServiceInstanceName().equals(name));
}
// verifies that the right query was enqueued with the right delay, and send query by executing // verifies that the right query was enqueued with the right delay, and send query by executing
// the runnable. // the runnable.
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) { private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) {