diff --git a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java index 84faf12036..2d5bb001f8 100644 --- a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java +++ b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java @@ -29,7 +29,6 @@ import com.android.server.connectivity.mdns.util.MdnsUtils; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.DatagramPacket; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; @@ -78,6 +77,7 @@ public class EnqueueMdnsQueryCallable implements Callable servicesToResolve; @NonNull private final MdnsResponseDecoder.Clock clock; + private final boolean onlyUseIpv6OnIpv6OnlyNetworks; EnqueueMdnsQueryCallable( @NonNull MdnsSocketClientBase requestSender, @@ -87,6 +87,7 @@ public class EnqueueMdnsQueryCallable implements Callable servicesToResolve, @NonNull MdnsResponseDecoder.Clock clock) { @@ -97,6 +98,7 @@ public class EnqueueMdnsQueryCallable implements Callable(servicesToResolve); this.clock = clock; @@ -128,24 +130,29 @@ public class EnqueueMdnsQueryCallable implements Callable(serviceName, MdnsRecord.TYPE_TXT)); - } - if (!response.hasServiceRecord() || MdnsUtils.isRecordRenewalNeeded( - response.getServiceRecord(), now)) { - missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_SRV)); - // The hostname is not yet known, so queries for address records will be sent - // the next time the EnqueueMdnsQueryCallable is enqueued if the reply does not - // contain them. In practice, advertisers should include the address records - // when queried for SRV, although it's not a MUST requirement (RFC6763 12.2). - // TODO: Figure out how to renew the A/AAAA record. Usually A/AAAA record will - // be included in the response to the SRV record so in high chances there is - // no need to renew them individually. - } else if (!response.hasInet4AddressRecord() && !response.hasInet6AddressRecord()) { - final String[] host = response.getServiceRecord().getServiceHost(); - missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_A)); - missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_AAAA)); + boolean renewTxt = !response.hasTextRecord() || MdnsUtils.isRecordRenewalNeeded( + response.getTextRecord(), now); + boolean renewSrv = !response.hasServiceRecord() || MdnsUtils.isRecordRenewalNeeded( + response.getServiceRecord(), now); + if (renewSrv && renewTxt) { + missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_ANY)); + } else { + if (renewTxt) { + missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_TXT)); + } + if (renewSrv) { + missingKnownAnswerRecords.add(new Pair<>(serviceName, MdnsRecord.TYPE_SRV)); + // The hostname is not yet known, so queries for address records will be + // sent the next time the EnqueueMdnsQueryCallable is enqueued if the reply + // does not contain them. In practice, advertisers should include the + // address records when queried for SRV, although it's not a MUST + // requirement (RFC6763 12.2). + } else if (!response.hasInet4AddressRecord() + && !response.hasInet6AddressRecord()) { + final String[] host = response.getServiceRecord().getServiceHost(); + missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_A)); + missingKnownAnswerRecords.add(new Pair<>(host, MdnsRecord.TYPE_AAAA)); + } } } numQuestions += missingKnownAnswerRecords.size(); @@ -183,24 +190,9 @@ public class EnqueueMdnsQueryCallable implements Callable activeSockets = getActiveSockets(); + boolean shouldQueryIpv6 = !onlyUseIpv6OnIpv6OnlyNetworks || isIpv6OnlyNetworks( + activeSockets, targetNetwork); for (int i = 0; i < activeSockets.size(); i++) { final MdnsInterfaceSocket socket = activeSockets.keyAt(i); final Network network = activeSockets.valueAt(i).getNetwork(); // Check ip capability and network before sending packet - if (((isIpv6 && socket.hasJoinedIpv6()) || (isIpv4 && socket.hasJoinedIpv4())) + if (((isIpv6 && socket.hasJoinedIpv6() && shouldQueryIpv6) + || (isIpv4 && socket.hasJoinedIpv4())) // Contrary to MdnsUtils.isNetworkMatched, only send packets targeting // the null network to interfaces that have the null network (tethering // downstream interfaces). @@ -237,6 +241,19 @@ public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase { } } + private boolean isIpv6OnlyNetworks( + @NonNull ArrayMap activeSockets, + @Nullable Network targetNetwork) { + for (int i = 0; i < activeSockets.size(); i++) { + final MdnsInterfaceSocket socket = activeSockets.keyAt(i); + final Network network = activeSockets.valueAt(i).getNetwork(); + if (Objects.equals(network, targetNetwork) && socket.hasJoinedIpv4()) { + return false; + } + } + return true; + } + private void processResponsePacket(byte[] recvbuf, int length, @NonNull SocketKey socketKey) { int packetNumber = ++mReceivedPacketNumber; @@ -259,21 +276,38 @@ public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase { } /** - * Sends a mDNS request packet via given network that asks for multicast response. Null network - * means sending packet via all networks. + * Send a mDNS request packet via given network that asks for multicast response. + * + *

The socket client may use a null network to identify some or all interfaces, in which case + * passing null sends the packet to these. */ + public void sendPacketRequestingMulticastResponse(@NonNull DatagramPacket packet, + @Nullable Network network, boolean onlyUseIpv6OnIpv6OnlyNetworks) { + mHandler.post(() -> sendMdnsPacket(packet, network, onlyUseIpv6OnIpv6OnlyNetworks)); + } + @Override - public void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { - mHandler.post(() -> sendMdnsPacket(packet, network)); + public void sendPacketRequestingMulticastResponse( + @NonNull DatagramPacket packet, boolean onlyUseIpv6OnIpv6OnlyNetworks) { + sendPacketRequestingMulticastResponse( + packet, null /* network */, onlyUseIpv6OnIpv6OnlyNetworks); } /** - * Sends a mDNS request packet via given network that asks for unicast response. Null network - * means sending packet via all networks. + * Send a mDNS request packet via given network that asks for unicast response. + * + *

The socket client may use a null network to identify some or all interfaces, in which case + * passing null sends the packet to these. */ - @Override - public void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { - // TODO: Separate unicast packet. - mHandler.post(() -> sendMdnsPacket(packet, network)); + public void sendPacketRequestingUnicastResponse(@NonNull DatagramPacket packet, + @Nullable Network network, boolean onlyUseIpv6OnIpv6OnlyNetworks) { + mHandler.post(() -> sendMdnsPacket(packet, network, onlyUseIpv6OnIpv6OnlyNetworks)); } -} + + @Override + public void sendPacketRequestingUnicastResponse( + @NonNull DatagramPacket packet, boolean onlyUseIpv6OnIpv6OnlyNetworks) { + sendPacketRequestingUnicastResponse( + packet, null /* network */, onlyUseIpv6OnIpv6OnlyNetworks); + } +} \ No newline at end of file diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java index 3da6bd0105..98c80ee7f1 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSearchOptions.java @@ -44,10 +44,13 @@ public class MdnsSearchOptions implements Parcelable { new Parcelable.Creator() { @Override public MdnsSearchOptions createFromParcel(Parcel source) { - return new MdnsSearchOptions(source.createStringArrayList(), - source.readBoolean(), source.readBoolean(), + return new MdnsSearchOptions( + source.createStringArrayList(), + source.readBoolean(), + source.readBoolean(), source.readParcelable(null), - source.readString()); + source.readString(), + (source.dataAvail() > 0) ? source.readBoolean() : false); } @Override @@ -61,18 +64,25 @@ public class MdnsSearchOptions implements Parcelable { private final String resolveInstanceName; private final boolean isPassiveMode; + private final boolean onlyUseIpv6OnIpv6OnlyNetworks; private final boolean removeExpiredService; // The target network for searching. Null network means search on all possible interfaces. @Nullable private final Network mNetwork; /** Parcelable constructs for a {@link MdnsSearchOptions}. */ - MdnsSearchOptions(List subtypes, boolean isPassiveMode, boolean removeExpiredService, - @Nullable Network network, @Nullable String resolveInstanceName) { + MdnsSearchOptions( + List subtypes, + boolean isPassiveMode, + boolean removeExpiredService, + @Nullable Network network, + @Nullable String resolveInstanceName, + boolean onlyUseIpv6OnIpv6OnlyNetworks) { this.subtypes = new ArrayList<>(); if (subtypes != null) { this.subtypes.addAll(subtypes); } this.isPassiveMode = isPassiveMode; + this.onlyUseIpv6OnIpv6OnlyNetworks = onlyUseIpv6OnIpv6OnlyNetworks; this.removeExpiredService = removeExpiredService; mNetwork = network; this.resolveInstanceName = resolveInstanceName; @@ -104,6 +114,14 @@ public class MdnsSearchOptions implements Parcelable { return isPassiveMode; } + /** + * @return {@code true} if only the IPv4 mDNS host should be queried on network that supports + * both IPv6 as well as IPv4. On an IPv6-only network, this is ignored. + */ + public boolean onlyUseIpv6OnIpv6OnlyNetworks() { + return onlyUseIpv6OnIpv6OnlyNetworks; + } + /** Returns {@code true} if service will be removed after its TTL expires. */ public boolean removeExpiredService() { return removeExpiredService; @@ -140,12 +158,14 @@ public class MdnsSearchOptions implements Parcelable { out.writeBoolean(removeExpiredService); out.writeParcelable(mNetwork, 0); out.writeString(resolveInstanceName); + out.writeBoolean(onlyUseIpv6OnIpv6OnlyNetworks); } /** A builder to create {@link MdnsSearchOptions}. */ public static final class Builder { private final Set subtypes; private boolean isPassiveMode = true; + private boolean onlyUseIpv6OnIpv6OnlyNetworks = false; private boolean removeExpiredService; private Network mNetwork; private String resolveInstanceName; @@ -189,6 +209,15 @@ public class MdnsSearchOptions implements Parcelable { return this; } + /** + * Sets if only the IPv4 mDNS host should be queried on a network that is both IPv4 & IPv6. + * On an IPv6-only network, this is ignored. + */ + public Builder setOnlyUseIpv6OnIpv6OnlyNetworks(boolean onlyUseIpv6OnIpv6OnlyNetworks) { + this.onlyUseIpv6OnIpv6OnlyNetworks = onlyUseIpv6OnIpv6OnlyNetworks; + return this; + } + /** * Sets if the service should be removed after TTL. * @@ -223,8 +252,13 @@ public class MdnsSearchOptions implements Parcelable { /** Builds a {@link MdnsSearchOptions} with the arguments supplied to this builder. */ public MdnsSearchOptions build() { - return new MdnsSearchOptions(new ArrayList<>(subtypes), isPassiveMode, - removeExpiredService, mNetwork, resolveInstanceName); + return new MdnsSearchOptions( + new ArrayList<>(subtypes), + isPassiveMode, + removeExpiredService, + mNetwork, + resolveInstanceName, + onlyUseIpv6OnIpv6OnlyNetworks); } } } \ No newline at end of file diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java index bdc673e1df..a36eb1bb0f 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java @@ -198,6 +198,7 @@ public class MdnsServiceTypeClient { final QueryTaskConfig taskConfig = new QueryTaskConfig( searchOptions.getSubtypes(), searchOptions.isPassiveMode(), + searchOptions.onlyUseIpv6OnIpv6OnlyNetworks(), currentSessionId, socketKey); if (hadReply) { @@ -220,7 +221,7 @@ public class MdnsServiceTypeClient { final boolean matchesInstanceName = options.getResolveInstanceName() == null // DNS is case-insensitive, so ignore case in the comparison || MdnsUtils.equalsIgnoreDnsCase(options.getResolveInstanceName(), - response.getServiceInstanceName()); + response.getServiceInstanceName()); // If discovery is requiring some subtypes, the response must have one that matches a // requested one. @@ -427,6 +428,7 @@ public class MdnsServiceTypeClient { private final boolean alwaysAskForUnicastResponse = MdnsConfigs.alwaysAskForUnicastResponseInEachBurst(); private final boolean usePassiveMode; + private final boolean onlyUseIpv6OnIpv6OnlyNetworks; private final long sessionId; @VisibleForTesting int transactionId; @@ -439,9 +441,13 @@ public class MdnsServiceTypeClient { private boolean isFirstBurst; @NonNull private final SocketKey socketKey; - QueryTaskConfig(@NonNull Collection subtypes, boolean usePassiveMode, - long sessionId, @NonNull SocketKey socketKey) { + QueryTaskConfig(@NonNull Collection subtypes, + boolean usePassiveMode, + boolean onlyUseIpv6OnIpv6OnlyNetworks, + long sessionId, + @Nullable SocketKey socketKey) { this.usePassiveMode = usePassiveMode; + this.onlyUseIpv6OnIpv6OnlyNetworks = onlyUseIpv6OnIpv6OnlyNetworks; this.subtypes = new ArrayList<>(subtypes); this.queriesPerBurst = QUERIES_PER_BURST; this.burstCounter = 0; @@ -559,6 +565,7 @@ public class MdnsServiceTypeClient { config.expectUnicastResponse, config.transactionId, config.socketKey.getNetwork(), + config.onlyUseIpv6OnIpv6OnlyNetworks, sendDiscoveryQueries, servicesToResolve, clock) diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java index 5fd13548f4..cdd9f76199 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java @@ -93,6 +93,10 @@ public class MdnsSocket { } for (NetworkInterfaceWrapper networkInterface : networkInterfaces) { multicastSocket.joinGroup(multicastAddress, networkInterface.getNetworkInterface()); + if (!isOnIPv6OnlyNetwork) { + multicastSocket.joinGroup( + MULTICAST_IPV6_ADDRESS, networkInterface.getNetworkInterface()); + } } } @@ -105,6 +109,10 @@ public class MdnsSocket { } for (NetworkInterfaceWrapper networkInterface : networkInterfaces) { multicastSocket.leaveGroup(multicastAddress, networkInterface.getNetworkInterface()); + if (!isOnIPv6OnlyNetwork) { + multicastSocket.leaveGroup( + MULTICAST_IPV6_ADDRESS, networkInterface.getNetworkInterface()); + } } } diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java index 2b6e5d0d35..9c9812d0ed 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java @@ -31,6 +31,9 @@ import com.android.server.connectivity.mdns.util.MdnsLogger; import java.io.IOException; import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; @@ -194,38 +197,22 @@ public class MdnsSocketClient implements MdnsSocketClientBase { } } - /** Sends a mDNS request packet that asks for multicast response. */ - public void sendMulticastPacket(@NonNull DatagramPacket packet) { - sendMdnsPacket(packet, multicastPacketQueue); + @Override + public void sendPacketRequestingMulticastResponse(@NonNull DatagramPacket packet, + boolean onlyUseIpv6OnIpv6OnlyNetworks) { + sendMdnsPacket(packet, multicastPacketQueue, onlyUseIpv6OnIpv6OnlyNetworks); } - /** Sends a mDNS request packet that asks for unicast response. */ - public void sendUnicastPacket(DatagramPacket packet) { + @Override + public void sendPacketRequestingUnicastResponse(@NonNull DatagramPacket packet, + boolean onlyUseIpv6OnIpv6OnlyNetworks) { if (useSeparateSocketForUnicast) { - sendMdnsPacket(packet, unicastPacketQueue); + sendMdnsPacket(packet, unicastPacketQueue, onlyUseIpv6OnIpv6OnlyNetworks); } else { - sendMdnsPacket(packet, multicastPacketQueue); + sendMdnsPacket(packet, multicastPacketQueue, onlyUseIpv6OnIpv6OnlyNetworks); } } - @Override - public void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { - if (network != null) { - throw new IllegalArgumentException("This socket client does not support sending to " - + "specific networks"); - } - sendMulticastPacket(packet); - } - - @Override - public void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) { - if (network != null) { - throw new IllegalArgumentException("This socket client does not support sending to " - + "specific networks"); - } - sendUnicastPacket(packet); - } - @Override public void notifyNetworkRequested( @NonNull MdnsServiceBrowserListener listener, @@ -243,11 +230,25 @@ public class MdnsSocketClient implements MdnsSocketClientBase { return false; } - private void sendMdnsPacket(DatagramPacket packet, Queue packetQueueToUse) { + private void sendMdnsPacket(DatagramPacket packet, Queue packetQueueToUse, + boolean onlyUseIpv6OnIpv6OnlyNetworks) { if (shouldStopSocketLoop && !MdnsConfigs.allowAddMdnsPacketAfterDiscoveryStops()) { LOGGER.w("sendMdnsPacket() is called after discovery already stopped"); return; } + + final boolean isIpv4 = ((InetSocketAddress) packet.getSocketAddress()).getAddress() + instanceof Inet4Address; + final boolean isIpv6 = ((InetSocketAddress) packet.getSocketAddress()).getAddress() + instanceof Inet6Address; + final boolean ipv6Only = multicastSocket != null && multicastSocket.isOnIPv6OnlyNetwork(); + if (isIpv4 && ipv6Only) { + return; + } + if (isIpv6 && !ipv6Only && onlyUseIpv6OnIpv6OnlyNetworks) { + return; + } + synchronized (packetQueueToUse) { while (packetQueueToUse.size() >= MdnsConfigs.mdnsPacketQueueMaxSize()) { packetQueueToUse.remove(); @@ -535,8 +536,4 @@ public class MdnsSocketClient implements MdnsSocketClientBase { } packets.clear(); } - - public boolean isOnIPv6OnlyNetwork() { - return multicastSocket != null && multicastSocket.isOnIPv6OnlyNetwork(); - } } \ No newline at end of file diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java index a35925a9f9..5e4a8b58f7 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClientBase.java @@ -41,19 +41,15 @@ public interface MdnsSocketClientBase { /** * Send a mDNS request packet via given network that asks for multicast response. - * - *

The socket client may use a null network to identify some or all interfaces, in which case - * passing null sends the packet to these. */ - void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network); + void sendPacketRequestingMulticastResponse(@NonNull DatagramPacket packet, + boolean onlyUseIpv6OnIpv6OnlyNetworks); /** * Send a mDNS request packet via given network that asks for unicast response. - * - *

The socket client may use a null network to identify some or all interfaces, in which case - * passing null sends the packet to these. */ - void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network); + void sendPacketRequestingUnicastResponse(@NonNull DatagramPacket packet, + boolean onlyUseIpv6OnIpv6OnlyNetworks); /*** Notify that the given network is requested for mdns discovery / resolution */ void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener, @@ -88,4 +84,4 @@ public interface MdnsSocketClientBase { /*** Notify requested socket is destroyed */ void onAllSocketsDestroyed(@NonNull SocketKey socketKey); } -} +} \ No newline at end of file diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java index f7ef0778cb..b812fa6b70 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java @@ -138,18 +138,38 @@ public class MdnsMultinetworkSocketClientTest { verify(mSocketCreationCallback).onSocketCreated(tetherSocketKey2); // Send packet to IPv4 with target network and verify sending has been called. - mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork); + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, mNetwork, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(mSocket).send(ipv4Packet); verify(tetherIfaceSock1, never()).send(any()); verify(tetherIfaceSock2, never()).send(any()); + // Send packet to IPv4 with onlyUseIpv6OnIpv6OnlyNetworks = true, the packet will be sent. + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, mNetwork, + true /* onlyUseIpv6OnIpv6OnlyNetworks */); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket, times(2)).send(ipv4Packet); + verify(tetherIfaceSock1, never()).send(any()); + verify(tetherIfaceSock2, never()).send(any()); + // Send packet to IPv6 without target network and verify sending has been called. - mSocketClient.sendMulticastPacket(ipv6Packet, null); + mSocketClient.sendPacketRequestingMulticastResponse(ipv6Packet, null, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(mSocket, never()).send(ipv6Packet); verify(tetherIfaceSock1).send(ipv6Packet); verify(tetherIfaceSock2).send(ipv6Packet); + + // Send packet to IPv6 with onlyUseIpv6OnIpv6OnlyNetworks = true, the packet will not be + // sent. Therefore, the tetherIfaceSock1.send() and tetherIfaceSock2.send() are still be + // called once. + mSocketClient.sendPacketRequestingMulticastResponse(ipv6Packet, null, + true /* onlyUseIpv6OnIpv6OnlyNetworks */); + HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); + verify(mSocket, never()).send(ipv6Packet); + verify(tetherIfaceSock1, times(1)).send(ipv6Packet); + verify(tetherIfaceSock2, times(1)).send(ipv6Packet); } @Test @@ -230,7 +250,8 @@ public class MdnsMultinetworkSocketClientTest { verify(mSocketCreationCallback).onSocketCreated(socketKey3); // Send IPv4 packet on the non-null Network and verify sending has been called. - mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork); + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, mNetwork, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(mSocket).send(ipv4Packet); verify(socket2, never()).send(any()); @@ -258,7 +279,8 @@ public class MdnsMultinetworkSocketClientTest { verify(socketCreationCb2).onSocketCreated(socketKey3); // Send IPv4 packet to null network and verify sending to the 2 tethered interface sockets. - mSocketClient.sendMulticastPacket(ipv4Packet, null); + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, null, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); // ipv4Packet still sent only once on mSocket: times(1) matches the packet sent earlier on // mNetwork @@ -271,7 +293,8 @@ public class MdnsMultinetworkSocketClientTest { verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback2); // Send IPv4 packet again and verify it's still sent a second time - mSocketClient.sendMulticastPacket(ipv4Packet, null); + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, null, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(socket2, times(2)).send(ipv4Packet); verify(socket3, times(2)).send(ipv4Packet); @@ -281,7 +304,8 @@ public class MdnsMultinetworkSocketClientTest { verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback); // Send IPv4 packet and verify no more sending. - mSocketClient.sendMulticastPacket(ipv4Packet, null); + mSocketClient.sendPacketRequestingMulticastResponse(ipv4Packet, null, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT); verify(mSocket, times(1)).send(ipv4Packet); verify(socket2, times(2)).send(ipv4Packet); diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java index 635a1d4240..9892e9fad8 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java @@ -327,7 +327,8 @@ public class MdnsServiceTypeClientTests { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); QueryTaskConfig config = new QueryTaskConfig( - searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1, socketKey); + searchOptions.getSubtypes(), searchOptions.isPassiveMode(), + false /* onlyUseIpv6OnIpv6OnlyNetworks */, 1, socketKey); // This is the first query. We will ask for unicast response. assertTrue(config.expectUnicastResponse); @@ -356,7 +357,8 @@ public class MdnsServiceTypeClientTests { MdnsSearchOptions searchOptions = MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build(); QueryTaskConfig config = new QueryTaskConfig( - searchOptions.getSubtypes(), searchOptions.isPassiveMode(), 1, socketKey); + searchOptions.getSubtypes(), searchOptions.isPassiveMode(), + false /* onlyUseIpv6OnIpv6OnlyNetworks */, 1, socketKey); // This is the first query. We will ask for unicast response. assertTrue(config.expectUnicastResponse); @@ -928,16 +930,16 @@ public class MdnsServiceTypeClientTests { ArgumentCaptor.forClass(DatagramPacket.class); currentThreadExecutor.getAndClearLastScheduledRunnable().run(); // Send twice for IPv4 and IPv6 - inOrder.verify(mockSocketClient, times(2)).sendUnicastPacket(srvTxtQueryCaptor.capture(), - eq(mockNetwork)); + inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse( + srvTxtQueryCaptor.capture(), + eq(mockNetwork), eq(false)); final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse( new MdnsPacketReader(srvTxtQueryCaptor.getValue())); final String[] serviceName = getTestServiceName(instanceName); assertFalse(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_PTR)); - assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_SRV, serviceName)); - assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_TXT, serviceName)); + assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_ANY, serviceName)); // Process a response with SRV+TXT final MdnsPacket srvTxtResponse = new MdnsPacket( @@ -959,8 +961,9 @@ public class MdnsServiceTypeClientTests { final ArgumentCaptor addressQueryCaptor = ArgumentCaptor.forClass(DatagramPacket.class); currentThreadExecutor.getAndClearLastScheduledRunnable().run(); - inOrder.verify(mockSocketClient, times(2)).sendMulticastPacket(addressQueryCaptor.capture(), - eq(mockNetwork)); + inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingMulticastResponse( + addressQueryCaptor.capture(), + eq(mockNetwork), eq(false)); final MdnsPacket addressQueryPacket = MdnsPacket.parse( new MdnsPacketReader(addressQueryCaptor.getValue())); @@ -1018,15 +1021,15 @@ public class MdnsServiceTypeClientTests { ArgumentCaptor.forClass(DatagramPacket.class); currentThreadExecutor.getAndClearLastScheduledRunnable().run(); // Send twice for IPv4 and IPv6 - inOrder.verify(mockSocketClient, times(2)).sendUnicastPacket(srvTxtQueryCaptor.capture(), - eq(mockNetwork)); + inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse( + srvTxtQueryCaptor.capture(), + eq(mockNetwork), eq(false)); final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse( new MdnsPacketReader(srvTxtQueryCaptor.getValue())); final String[] serviceName = getTestServiceName(instanceName); - assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_SRV, serviceName)); - assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_TXT, serviceName)); + assertTrue(hasQuestion(srvTxtQueryPacket, MdnsRecord.TYPE_ANY, serviceName)); // Process a response with all records final MdnsPacket srvTxtResponse = new MdnsPacket( @@ -1064,13 +1067,13 @@ public class MdnsServiceTypeClientTests { final ArgumentCaptor renewalQueryCaptor = ArgumentCaptor.forClass(DatagramPacket.class); // Second and later sends are sent as "expect multicast response" queries - inOrder.verify(mockSocketClient, times(2)).sendMulticastPacket(renewalQueryCaptor.capture(), - eq(mockNetwork)); + inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingMulticastResponse( + renewalQueryCaptor.capture(), + eq(mockNetwork), eq(false)); inOrder.verify(mockListenerOne).onDiscoveryQuerySent(any(), anyInt()); final MdnsPacket renewalPacket = MdnsPacket.parse( new MdnsPacketReader(renewalQueryCaptor.getValue())); - assertTrue(hasQuestion(renewalPacket, MdnsRecord.TYPE_SRV, serviceName)); - assertTrue(hasQuestion(renewalPacket, MdnsRecord.TYPE_TXT, serviceName)); + assertTrue(hasQuestion(renewalPacket, MdnsRecord.TYPE_ANY, serviceName)); inOrder.verifyNoMoreInteractions(); long updatedReceiptTime = TEST_ELAPSED_REALTIME + TEST_TTL; @@ -1328,18 +1331,18 @@ public class MdnsServiceTypeClientTests { assertEquals(currentThreadExecutor.getAndClearLastScheduledDelayInMs(), timeInMs); currentThreadExecutor.getAndClearLastScheduledRunnable().run(); if (expectsUnicastResponse) { - verify(mockSocketClient).sendUnicastPacket( - expectedIPv4Packets[index], mockNetwork); + verify(mockSocketClient).sendPacketRequestingUnicastResponse( + expectedIPv4Packets[index], mockNetwork, false); if (multipleSocketDiscovery) { - verify(mockSocketClient).sendUnicastPacket( - expectedIPv6Packets[index], mockNetwork); + verify(mockSocketClient).sendPacketRequestingUnicastResponse( + expectedIPv6Packets[index], mockNetwork, false); } } else { - verify(mockSocketClient).sendMulticastPacket( - expectedIPv4Packets[index], mockNetwork); + verify(mockSocketClient).sendPacketRequestingMulticastResponse( + expectedIPv4Packets[index], mockNetwork, false); if (multipleSocketDiscovery) { - verify(mockSocketClient).sendMulticastPacket( - expectedIPv6Packets[index], mockNetwork); + verify(mockSocketClient).sendPacketRequestingMulticastResponse( + expectedIPv6Packets[index], mockNetwork, false); } } } diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java index e30c2496d5..69efc61431 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java @@ -54,6 +54,7 @@ import org.mockito.invocation.InvocationOnMock; import java.io.IOException; import java.net.DatagramPacket; +import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -221,15 +222,17 @@ public class MdnsSocketClientTests { assertTrue(unicastReceiverThread.isAlive()); // Sends a packet. - DatagramPacket packet = new DatagramPacket(buf, 0, 5); - mdnsClient.sendMulticastPacket(packet); + DatagramPacket packet = getTestDatagramPacket(); + mdnsClient.sendPacketRequestingMulticastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); // mockMulticastSocket.send() will be called on another thread. If we verify it immediately, // it may not be called yet. So timeout is added. verify(mockMulticastSocket, timeout(TIMEOUT).times(1)).send(packet); verify(mockUnicastSocket, timeout(TIMEOUT).times(0)).send(packet); // Verify the packet is sent by the unicast socket. - mdnsClient.sendUnicastPacket(packet); + mdnsClient.sendPacketRequestingUnicastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); verify(mockMulticastSocket, timeout(TIMEOUT).times(1)).send(packet); verify(mockUnicastSocket, timeout(TIMEOUT).times(1)).send(packet); @@ -272,15 +275,17 @@ public class MdnsSocketClientTests { assertNull(unicastReceiverThread); // Sends a packet. - DatagramPacket packet = new DatagramPacket(buf, 0, 5); - mdnsClient.sendMulticastPacket(packet); + DatagramPacket packet = getTestDatagramPacket(); + mdnsClient.sendPacketRequestingMulticastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); // mockMulticastSocket.send() will be called on another thread. If we verify it immediately, // it may not be called yet. So timeout is added. verify(mockMulticastSocket, timeout(TIMEOUT).times(1)).send(packet); verify(mockUnicastSocket, timeout(TIMEOUT).times(0)).send(packet); // Verify the packet is sent by the multicast socket as well. - mdnsClient.sendUnicastPacket(packet); + mdnsClient.sendPacketRequestingUnicastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); verify(mockMulticastSocket, timeout(TIMEOUT).times(2)).send(packet); verify(mockUnicastSocket, timeout(TIMEOUT).times(0)).send(packet); @@ -332,7 +337,8 @@ public class MdnsSocketClientTests { public void testStopDiscovery_queueIsCleared() throws IOException { mdnsClient.startDiscovery(); mdnsClient.stopDiscovery(); - mdnsClient.sendMulticastPacket(new DatagramPacket(buf, 0, 5)); + mdnsClient.sendPacketRequestingMulticastResponse(getTestDatagramPacket(), + false /* onlyUseIpv6OnIpv6OnlyNetworks */); synchronized (mdnsClient.multicastPacketQueue) { assertTrue(mdnsClient.multicastPacketQueue.isEmpty()); @@ -343,7 +349,8 @@ public class MdnsSocketClientTests { public void testSendPacket_afterDiscoveryStops() throws IOException { mdnsClient.startDiscovery(); mdnsClient.stopDiscovery(); - mdnsClient.sendMulticastPacket(new DatagramPacket(buf, 0, 5)); + mdnsClient.sendPacketRequestingMulticastResponse(getTestDatagramPacket(), + false /* onlyUseIpv6OnIpv6OnlyNetworks */); synchronized (mdnsClient.multicastPacketQueue) { assertTrue(mdnsClient.multicastPacketQueue.isEmpty()); @@ -356,7 +363,8 @@ public class MdnsSocketClientTests { //MdnsConfigsFlagsImpl.mdnsPacketQueueMaxSize.override(2L); mdnsClient.startDiscovery(); for (int i = 0; i < 100; i++) { - mdnsClient.sendMulticastPacket(new DatagramPacket(buf, 0, 5)); + mdnsClient.sendPacketRequestingMulticastResponse(getTestDatagramPacket(), + false /* onlyUseIpv6OnIpv6OnlyNetworks */); } synchronized (mdnsClient.multicastPacketQueue) { @@ -452,9 +460,11 @@ public class MdnsSocketClientTests { enableUnicastResponse.set(true); mdnsClient.startDiscovery(); - DatagramPacket packet = new DatagramPacket(buf, 0, 5); - mdnsClient.sendUnicastPacket(packet); - mdnsClient.sendMulticastPacket(packet); + DatagramPacket packet = getTestDatagramPacket(); + mdnsClient.sendPacketRequestingUnicastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); + mdnsClient.sendPacketRequestingMulticastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); // Wait for the timer to be triggered. Thread.sleep(MdnsConfigs.checkMulticastResponseIntervalMs() * 2); @@ -484,8 +494,10 @@ public class MdnsSocketClientTests { assertFalse(mdnsClient.receivedUnicastResponse); assertFalse(mdnsClient.cannotReceiveMulticastResponse.get()); - mdnsClient.sendUnicastPacket(packet); - mdnsClient.sendMulticastPacket(packet); + mdnsClient.sendPacketRequestingUnicastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); + mdnsClient.sendPacketRequestingMulticastResponse(packet, + false /* onlyUseIpv6OnIpv6OnlyNetworks */); Thread.sleep(MdnsConfigs.checkMulticastResponseIntervalMs() * 2); // Verify cannotReceiveMulticastResponse is not set the true because we didn't receive the @@ -540,4 +552,9 @@ public class MdnsSocketClientTests { verify(mockCallback, timeout(TIMEOUT).atLeast(1)) .onResponseReceived(any(), argThat(key -> key.getInterfaceIndex() == -1)); } + + private DatagramPacket getTestDatagramPacket() { + return new DatagramPacket(buf, 0, 5, + new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), 5353 /* port */)); + } } \ No newline at end of file