Skip to content
Snippets Groups Projects
Commit b206809a authored by Handa Wang's avatar Handa Wang Committed by Gerrit Code Review
Browse files

Merge "Add a test case that a Border Router sends a UDP message to Thread device" into main

parents 1ec06555 b5c6ac2f
No related branches found
No related tags found
No related merge requests found
......@@ -21,10 +21,12 @@ import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_LEADER;
import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
import static android.net.thread.utils.IntegrationTestUtils.JOIN_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv6Packet;
import static android.net.thread.utils.IntegrationTestUtils.isSimulatedThreadRadioSupported;
import static android.net.thread.utils.IntegrationTestUtils.newPacketReader;
import static android.net.thread.utils.IntegrationTestUtils.readPacketFrom;
import static android.net.thread.utils.IntegrationTestUtils.sendUdpMessage;
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
import static android.net.thread.utils.IntegrationTestUtils.waitForStateAnyOf;
......@@ -35,10 +37,13 @@ import static com.android.testutils.TestPermissionUtil.runAsShell;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context;
import android.net.LinkProperties;
import android.net.MacAddress;
......@@ -62,6 +67,7 @@ import org.junit.runner.RunWith;
import java.net.Inet6Address;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
......@@ -187,4 +193,44 @@ public class BorderRoutingTest {
infraNetworkReader,
p -> isExpectedIcmpv6Packet(p, ICMPV6_ECHO_REPLY_TYPE)));
}
@Test
public void unicastRouting_borderRouterSendsUdpToThreadDevice_datagramReceived()
throws Exception {
assumeTrue(isSimulatedThreadRadioSupported());
/*
* <pre>
* Topology:
* Thread
* Border Router -------------- Full Thread device
* (Cuttlefish)
* </pre>
*/
// BR forms a network.
CompletableFuture<Void> joinFuture = new CompletableFuture<>();
runAsShell(
PERMISSION_THREAD_NETWORK_PRIVILEGED,
() -> mController.join(DEFAULT_DATASET, directExecutor(), joinFuture::complete));
joinFuture.get(RESTART_JOIN_TIMEOUT.toMillis(), MILLISECONDS);
// Creates a Full Thread Device (FTD) and lets it join the network.
FullThreadDevice ftd = new FullThreadDevice(6 /* node ID */);
ftd.joinNetwork(DEFAULT_DATASET);
ftd.waitForStateAnyOf(List.of("router", "child"), JOIN_TIMEOUT);
waitFor(() -> ftd.getOmrAddress() != null, Duration.ofSeconds(60));
Inet6Address ftdOmr = ftd.getOmrAddress();
assertNotNull(ftdOmr);
Inet6Address ftdMlEid = ftd.getMlEid();
assertNotNull(ftdMlEid);
ftd.udpBind(ftdOmr, 12345);
sendUdpMessage(ftdOmr, 12345, "aaaaaaaa");
assertEquals("aaaaaaaa", ftd.udpReceive());
ftd.udpBind(ftdMlEid, 12345);
sendUdpMessage(ftdMlEid, 12345, "bbbbbbbb");
assertEquals("bbbbbbbb", ftd.udpReceive());
}
}
......@@ -35,6 +35,8 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A class that launches and controls a simulation Full Thread Device (FTD).
......@@ -94,6 +96,12 @@ public final class FullThreadDevice {
return null;
}
/** Returns the Mesh-local EID address on this device if any. */
public Inet6Address getMlEid() {
List<String> addresses = executeCommand("ipaddr mleid");
return (Inet6Address) InetAddresses.parseNumericAddress(addresses.get(0));
}
/**
* Joins the Thread network using the given {@link ActiveOperationalDataset}.
*
......@@ -132,6 +140,33 @@ public final class FullThreadDevice {
return executeCommand("state").get(0);
}
/** Closes the UDP socket. */
public void udpClose() {
executeCommand("udp close");
}
/** Opens the UDP socket. */
public void udpOpen() {
executeCommand("udp open");
}
/** Opens the UDP socket and binds it to a specific address and port. */
public void udpBind(Inet6Address address, int port) {
udpClose();
udpOpen();
executeCommand(String.format("udp bind %s %d", address.getHostAddress(), port));
}
/** Returns the message received on the UDP socket. */
public String udpReceive() throws IOException {
Pattern pattern =
Pattern.compile("> (\\d+) bytes from ([\\da-f:]+) (\\d+) ([\\x00-\\x7F]+)");
Matcher matcher = pattern.matcher(mReader.readLine());
matcher.matches();
return matcher.group(4);
}
/** Runs the "factoryreset" command on the device. */
public void factoryReset() {
try {
......
......@@ -39,6 +39,12 @@ import com.android.testutils.TapPacketReader;
import com.google.common.util.concurrent.SettableFuture;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.ArrayList;
......@@ -219,4 +225,26 @@ public final class IntegrationTestUtils {
}
return pioList;
}
/**
* Sends a UDP message to a destination.
*
* @param dstAddress the IP address of the destination
* @param dstPort the port of the destination
* @param message the message in UDP payload
* @throws IOException if failed to send the message
*/
public static void sendUdpMessage(InetAddress dstAddress, int dstPort, String message)
throws IOException {
SocketAddress dstSockAddr = new InetSocketAddress(dstAddress, dstPort);
try (DatagramSocket socket = new DatagramSocket()) {
socket.connect(dstSockAddr);
byte[] msgBytes = message.getBytes();
DatagramPacket packet = new DatagramPacket(msgBytes, msgBytes.length);
socket.send(packet);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment