Adds option to control whethert to send IPv6 packet on IPv6 only network

Add options to control whether only send IPv6 packet on IPv6 only
network. In some use case, IPv6 query should not be sent on a dual
network.

Added a small improvement to send an ANY query if both SRV & PTR
records are needed.

Bug: 284480254
Test: atest CtsNetTest FrameworksNetTests
Change-Id: I8f55db6f5e8ae606ac167fb363bc9b2fb9b5fc14
This commit is contained in:
Yuyang Huang
2023-06-02 13:38:29 +09:00
parent d925df8aa6
commit 9637e84eed
10 changed files with 276 additions and 163 deletions

View File

@@ -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);

View File

@@ -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<DatagramPacket> 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<DatagramPacket> 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);
}
}
}

View File

@@ -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 */));
}
}