Only send to downstream ifaces for null network
When sendMulticastPacket or sendUnicastPacket is called with the null network, only send the packets to interfaces indexed with null, instead of all interfaces. When using MdnsMultinetworkSocketClient sending packets on the null network means sending on tethered downstream interfaces. When MdnsSocketClient is used (not used in the Android tree), sending on the null network sends on all interfaces as MdnsSocketClient does not support specific networks. This is clarified by explicitly throwing when a non-null Network is attempted to be used with MdnsSocketClient (but MdnsSocketClient is only used for tests in the Android tree). Bug: 283708537 Test: atest (cherry picked from https://android-review.googlesource.com/q/commit:87c374a37ac8698a98d0c35a3196922c69549cc7) Merged-In: Ia0186bf8aa2e0fc5878d6071fd23599df8488616 Change-Id: Ia0186bf8aa2e0fc5878d6071fd23599df8488616
This commit is contained in:
committed by
Cherrypicker Worker
parent
e82a699fc7
commit
85ff5b1323
@@ -211,7 +211,7 @@ public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<Str
|
||||
| (expectUnicastResponse ? MdnsConstants.QCLASS_UNICAST : 0));
|
||||
}
|
||||
|
||||
private void sendPacketTo(MdnsSocketClientBase requestSender, InetSocketAddress address)
|
||||
private void sendPacketTo(MdnsSocketClient requestSender, InetSocketAddress address)
|
||||
throws IOException {
|
||||
DatagramPacket packet = packetWriter.getPacket(address);
|
||||
if (expectUnicastResponse) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.server.connectivity.mdns;
|
||||
|
||||
import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
|
||||
import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -34,6 +33,7 @@ import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The {@link MdnsMultinetworkSocketClient} manages the multinetwork socket for mDns
|
||||
@@ -216,7 +216,10 @@ public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase {
|
||||
final Network network = activeSockets.valueAt(i);
|
||||
// Check ip capability and network before sending packet
|
||||
if (((isIpv6 && socket.hasJoinedIpv6()) || (isIpv4 && socket.hasJoinedIpv4()))
|
||||
&& isNetworkMatched(targetNetwork, network)) {
|
||||
// Contrary to MdnsUtils.isNetworkMatched, only send packets targeting
|
||||
// the null network to interfaces that have the null network (tethering
|
||||
// downstream interfaces).
|
||||
&& Objects.equals(network, targetNetwork)) {
|
||||
try {
|
||||
socket.send(packet);
|
||||
} catch (IOException e) {
|
||||
@@ -248,12 +251,6 @@ public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase {
|
||||
}
|
||||
}
|
||||
|
||||
/** Sends a mDNS request packet that asks for multicast response. */
|
||||
@Override
|
||||
public void sendMulticastPacket(@NonNull DatagramPacket packet) {
|
||||
sendMulticastPacket(packet, null /* network */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a mDNS request packet via given network that asks for multicast response. Null network
|
||||
* means sending packet via all networks.
|
||||
@@ -263,12 +260,6 @@ public class MdnsMultinetworkSocketClient implements MdnsSocketClientBase {
|
||||
mHandler.post(() -> sendMdnsPacket(packet, network));
|
||||
}
|
||||
|
||||
/** Sends a mDNS request packet that asks for unicast response. */
|
||||
@Override
|
||||
public void sendUnicastPacket(@NonNull DatagramPacket packet) {
|
||||
sendUnicastPacket(packet, null /* network */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a mDNS request packet via given network that asks for unicast response. Null network
|
||||
* means sending packet via all networks.
|
||||
|
||||
@@ -195,13 +195,11 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
|
||||
}
|
||||
|
||||
/** Sends a mDNS request packet that asks for multicast response. */
|
||||
@Override
|
||||
public void sendMulticastPacket(@NonNull DatagramPacket packet) {
|
||||
sendMdnsPacket(packet, multicastPacketQueue);
|
||||
}
|
||||
|
||||
/** Sends a mDNS request packet that asks for unicast response. */
|
||||
@Override
|
||||
public void sendUnicastPacket(DatagramPacket packet) {
|
||||
if (useSeparateSocketForUnicast) {
|
||||
sendMdnsPacket(packet, unicastPacketQueue);
|
||||
@@ -210,6 +208,36 @@ public class MdnsSocketClient implements MdnsSocketClientBase {
|
||||
}
|
||||
}
|
||||
|
||||
@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,
|
||||
@Nullable Network network,
|
||||
@NonNull SocketCreationCallback socketCreationCallback) {
|
||||
if (network != null) {
|
||||
throw new IllegalArgumentException("This socket client does not support requesting "
|
||||
+ "specific networks");
|
||||
}
|
||||
socketCreationCallback.onSocketCreated(null);
|
||||
}
|
||||
|
||||
private void sendMdnsPacket(DatagramPacket packet, Queue<DatagramPacket> packetQueueToUse) {
|
||||
if (shouldStopSocketLoop && !MdnsConfigs.allowAddMdnsPacketAfterDiscoveryStops()) {
|
||||
LOGGER.w("sendMdnsPacket() is called after discovery already stopped");
|
||||
|
||||
@@ -38,35 +38,25 @@ public interface MdnsSocketClientBase {
|
||||
/*** Set callback for receiving mDns response */
|
||||
void setCallback(@Nullable Callback callback);
|
||||
|
||||
/*** Sends a mDNS request packet that asks for multicast response. */
|
||||
void sendMulticastPacket(@NonNull DatagramPacket packet);
|
||||
/**
|
||||
* Send a mDNS request packet via given network that asks for multicast response.
|
||||
*
|
||||
* <p>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);
|
||||
|
||||
/**
|
||||
* 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 unicast response.
|
||||
*
|
||||
* <p>The socket client may use a null network to identify some or all interfaces, in which case
|
||||
* passing null sends the packet to these.
|
||||
*/
|
||||
default void sendMulticastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This socket client doesn't support per-network sending");
|
||||
}
|
||||
|
||||
/*** Sends a mDNS request packet that asks for unicast response. */
|
||||
void sendUnicastPacket(@NonNull DatagramPacket packet);
|
||||
|
||||
/**
|
||||
* Sends a mDNS request packet via given network that asks for unicast response. Null network
|
||||
* means sending packet via all networks.
|
||||
*/
|
||||
default void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This socket client doesn't support per-network sending");
|
||||
}
|
||||
void sendUnicastPacket(@NonNull DatagramPacket packet, @Nullable Network network);
|
||||
|
||||
/*** Notify that the given network is requested for mdns discovery / resolution */
|
||||
default void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
|
||||
@Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback) {
|
||||
socketCreationCallback.onSocketCreated(network);
|
||||
}
|
||||
void notifyNetworkRequested(@NonNull MdnsServiceBrowserListener listener,
|
||||
@Nullable Network network, @NonNull SocketCreationCallback socketCreationCallback);
|
||||
|
||||
/*** Notify that the network is unrequested */
|
||||
default void notifyNetworkUnrequested(@NonNull MdnsServiceBrowserListener listener) { }
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
import com.android.net.module.util.HexDump;
|
||||
import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback;
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
import com.android.testutils.DevSdkIgnoreRunner;
|
||||
import com.android.testutils.HandlerUtils;
|
||||
@@ -66,7 +67,7 @@ public class MdnsMultinetworkSocketClientTest {
|
||||
@Mock private MdnsInterfaceSocket mSocket;
|
||||
@Mock private MdnsServiceBrowserListener mListener;
|
||||
@Mock private MdnsSocketClientBase.Callback mCallback;
|
||||
@Mock private MdnsSocketClientBase.SocketCreationCallback mSocketCreationCallback;
|
||||
@Mock private SocketCreationCallback mSocketCreationCallback;
|
||||
private MdnsMultinetworkSocketClient mSocketClient;
|
||||
private Handler mHandler;
|
||||
|
||||
@@ -113,22 +114,36 @@ public class MdnsMultinetworkSocketClientTest {
|
||||
InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */);
|
||||
final DatagramPacket ipv6Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length,
|
||||
InetAddresses.parseNumericAddress("2001:db8::"), 0 /* port */);
|
||||
doReturn(true).when(mSocket).hasJoinedIpv4();
|
||||
doReturn(true).when(mSocket).hasJoinedIpv6();
|
||||
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
|
||||
|
||||
final MdnsInterfaceSocket tetherIfaceSock1 = mock(MdnsInterfaceSocket.class);
|
||||
final MdnsInterfaceSocket tetherIfaceSock2 = mock(MdnsInterfaceSocket.class);
|
||||
for (MdnsInterfaceSocket socket : List.of(mSocket, tetherIfaceSock1, tetherIfaceSock2)) {
|
||||
doReturn(true).when(socket).hasJoinedIpv4();
|
||||
doReturn(true).when(socket).hasJoinedIpv6();
|
||||
doReturn(createEmptyNetworkInterface()).when(socket).getInterface();
|
||||
}
|
||||
|
||||
// Notify socket created
|
||||
callback.onSocketCreated(mNetwork, mSocket, List.of());
|
||||
verify(mSocketCreationCallback).onSocketCreated(mNetwork);
|
||||
callback.onSocketCreated(null, tetherIfaceSock1, List.of());
|
||||
verify(mSocketCreationCallback).onSocketCreated(null);
|
||||
callback.onSocketCreated(null, tetherIfaceSock2, List.of());
|
||||
verify(mSocketCreationCallback, times(2)).onSocketCreated(null);
|
||||
|
||||
// Send packet to IPv4 with target network and verify sending has been called.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket).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);
|
||||
mSocketClient.sendMulticastPacket(ipv6Packet, null);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket).send(ipv6Packet);
|
||||
verify(mSocket, never()).send(ipv6Packet);
|
||||
verify(tetherIfaceSock1).send(ipv6Packet);
|
||||
verify(tetherIfaceSock2).send(ipv6Packet);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,61 +196,86 @@ public class MdnsMultinetworkSocketClientTest {
|
||||
|
||||
@Test
|
||||
public void testSocketRemovedAfterNetworkUnrequested() throws IOException {
|
||||
// Request a socket
|
||||
final SocketCallback callback = expectSocketCallback(mListener, mNetwork);
|
||||
// Request sockets on all networks
|
||||
final SocketCallback callback = expectSocketCallback(mListener, null);
|
||||
final DatagramPacket ipv4Packet = new DatagramPacket(BUFFER, 0 /* offset */, BUFFER.length,
|
||||
InetAddresses.parseNumericAddress("192.0.2.1"), 0 /* port */);
|
||||
|
||||
// Notify 3 socket created, including 2 tethered interfaces (null network)
|
||||
final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
|
||||
final MdnsInterfaceSocket socket3 = mock(MdnsInterfaceSocket.class);
|
||||
doReturn(true).when(mSocket).hasJoinedIpv4();
|
||||
doReturn(true).when(mSocket).hasJoinedIpv6();
|
||||
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
|
||||
// Notify socket created
|
||||
callback.onSocketCreated(mNetwork, mSocket, List.of());
|
||||
verify(mSocketCreationCallback).onSocketCreated(mNetwork);
|
||||
|
||||
// Send IPv4 packet and verify sending has been called.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket).send(ipv4Packet);
|
||||
|
||||
// Request another socket with null network
|
||||
final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class);
|
||||
final Network network2 = mock(Network.class);
|
||||
final MdnsInterfaceSocket socket2 = mock(MdnsInterfaceSocket.class);
|
||||
final SocketCallback callback2 = expectSocketCallback(listener2, null);
|
||||
doReturn(true).when(socket2).hasJoinedIpv4();
|
||||
doReturn(true).when(socket2).hasJoinedIpv6();
|
||||
doReturn(true).when(socket3).hasJoinedIpv4();
|
||||
doReturn(true).when(socket3).hasJoinedIpv6();
|
||||
doReturn(createEmptyNetworkInterface()).when(mSocket).getInterface();
|
||||
doReturn(createEmptyNetworkInterface()).when(socket2).getInterface();
|
||||
// Notify socket created for two networks.
|
||||
callback2.onSocketCreated(mNetwork, mSocket, List.of());
|
||||
callback2.onSocketCreated(network2, socket2, List.of());
|
||||
verify(mSocketCreationCallback, times(2)).onSocketCreated(mNetwork);
|
||||
verify(mSocketCreationCallback).onSocketCreated(network2);
|
||||
doReturn(createEmptyNetworkInterface()).when(socket3).getInterface();
|
||||
|
||||
// Send IPv4 packet and verify sending to two sockets.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet);
|
||||
callback.onSocketCreated(mNetwork, mSocket, List.of());
|
||||
callback.onSocketCreated(null, socket2, List.of());
|
||||
callback.onSocketCreated(null, socket3, List.of());
|
||||
verify(mSocketCreationCallback).onSocketCreated(mNetwork);
|
||||
verify(mSocketCreationCallback, times(2)).onSocketCreated(null);
|
||||
|
||||
// Send IPv4 packet on the non-null Network and verify sending has been called.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet, mNetwork);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket, times(2)).send(ipv4Packet);
|
||||
verify(socket2).send(ipv4Packet);
|
||||
verify(mSocket).send(ipv4Packet);
|
||||
verify(socket2, never()).send(any());
|
||||
verify(socket3, never()).send(any());
|
||||
|
||||
// Unrequest another socket
|
||||
// Request another socket with null network, get the same interfaces
|
||||
final SocketCreationCallback socketCreationCb2 = mock(SocketCreationCallback.class);
|
||||
final MdnsServiceBrowserListener listener2 = mock(MdnsServiceBrowserListener.class);
|
||||
|
||||
// requestSocket is called a second time
|
||||
final ArgumentCaptor<SocketCallback> callback2Captor =
|
||||
ArgumentCaptor.forClass(SocketCallback.class);
|
||||
mHandler.post(() -> mSocketClient.notifyNetworkRequested(
|
||||
listener2, null, socketCreationCb2));
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mProvider, times(2)).requestSocket(eq(null), callback2Captor.capture());
|
||||
final SocketCallback callback2 = callback2Captor.getAllValues().get(1);
|
||||
|
||||
// Notify socket created for all networks.
|
||||
callback2.onSocketCreated(mNetwork, mSocket, List.of());
|
||||
callback2.onSocketCreated(null, socket2, List.of());
|
||||
callback2.onSocketCreated(null, socket3, List.of());
|
||||
verify(socketCreationCb2).onSocketCreated(mNetwork);
|
||||
verify(socketCreationCb2, times(2)).onSocketCreated(null);
|
||||
|
||||
// Send IPv4 packet to null network and verify sending to the 2 tethered interface sockets.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet, null);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
// ipv4Packet still sent only once on mSocket: times(1) matches the packet sent earlier on
|
||||
// mNetwork
|
||||
verify(mSocket, times(1)).send(ipv4Packet);
|
||||
verify(socket2).send(ipv4Packet);
|
||||
verify(socket3).send(ipv4Packet);
|
||||
|
||||
// Unregister the second request
|
||||
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(listener2));
|
||||
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback2);
|
||||
|
||||
// Send IPv4 packet again and verify only sending via mSocket
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet);
|
||||
// Send IPv4 packet again and verify it's still sent a second time
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet, null);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket, times(3)).send(ipv4Packet);
|
||||
verify(socket2).send(ipv4Packet);
|
||||
verify(socket2, times(2)).send(ipv4Packet);
|
||||
verify(socket3, times(2)).send(ipv4Packet);
|
||||
|
||||
// Unrequest remaining socket
|
||||
// Unrequest remaining sockets
|
||||
mHandler.post(() -> mSocketClient.notifyNetworkUnrequested(mListener));
|
||||
verify(mProvider, timeout(DEFAULT_TIMEOUT)).unrequestSocket(callback);
|
||||
|
||||
// Send IPv4 packet and verify no more sending.
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet);
|
||||
mSocketClient.sendMulticastPacket(ipv4Packet, null);
|
||||
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
|
||||
verify(mSocket, times(3)).send(ipv4Packet);
|
||||
verify(socket2).send(ipv4Packet);
|
||||
verify(mSocket, times(1)).send(ipv4Packet);
|
||||
verify(socket2, times(2)).send(ipv4Packet);
|
||||
verify(socket3, times(2)).send(ipv4Packet);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user