326b2e1344
Reviewed-by: alanb, dfuchs, chegar
197 lines
7.4 KiB
Java
197 lines
7.4 KiB
Java
/*
|
|
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
|
|
/* @test
|
|
* @bug 8014499 8219804
|
|
* @library /test/lib
|
|
* @summary Test for interference when two sockets are bound to the same
|
|
* port but joined to different multicast groups
|
|
* @run main Promiscuous
|
|
* @run main/othervm -Djava.net.preferIPv4Stack=true Promiscuous
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
import static java.lang.System.out;
|
|
|
|
import java.io.UncheckedIOException;
|
|
import java.net.*;
|
|
|
|
import jdk.test.lib.NetworkConfiguration;
|
|
import jdk.test.lib.net.IPSupport;
|
|
|
|
public class Promiscuous {
|
|
|
|
static final int TIMEOUT = 5 * 1000; // 5 secs
|
|
static int id = 1000;
|
|
|
|
static void receive(MulticastSocket mc, boolean datagramExpected, int id)
|
|
throws IOException
|
|
{
|
|
byte[] ba = new byte[100];
|
|
DatagramPacket p;
|
|
try {
|
|
String data = null;
|
|
while (true) {
|
|
p = new DatagramPacket(ba, ba.length);
|
|
mc.receive(p);
|
|
data = new String(p.getData(), 0, p.getLength(), "UTF-8");
|
|
if (data.length() > UUID.length() && data.startsWith(UUID)) {
|
|
data = data.substring(UUID.length());
|
|
break;
|
|
}
|
|
logUnexpected(p);
|
|
}
|
|
int recvId = Integer.parseInt(data);
|
|
if (datagramExpected) {
|
|
if (recvId != id)
|
|
throw new RuntimeException("Unexpected id, got " + recvId
|
|
+ ", expected: " + id);
|
|
out.printf("Received message as expected, %s\n", p.getAddress());
|
|
} else {
|
|
throw new RuntimeException("Unexpected message received, "
|
|
+ p.getAddress());
|
|
}
|
|
} catch (SocketTimeoutException e) {
|
|
if (datagramExpected)
|
|
throw new RuntimeException(mc.getLocalSocketAddress()
|
|
+ ": Expected message not received, "
|
|
+ e.getMessage());
|
|
else
|
|
out.printf("Message not received, as expected\n");
|
|
}
|
|
}
|
|
|
|
static void logUnexpected(DatagramPacket p) {
|
|
byte[] ba = p.getData();
|
|
System.out.printf("Unexpected packet: length: %d. First three bytes: %d, %d, %d\n",
|
|
p.getLength(), ba[0], ba[1], ba[2]);
|
|
}
|
|
|
|
static final String UUID; // process-id : currentTimeMillis
|
|
|
|
static {
|
|
String s1 = Long.toString(ProcessHandle.current().pid());
|
|
String s2 = Long.toString(System.currentTimeMillis());
|
|
UUID = "<" + s1 + s2 + ">";
|
|
}
|
|
|
|
static SocketAddress toSocketAddress(InetAddress group) {
|
|
return new InetSocketAddress(group, 0);
|
|
}
|
|
|
|
static void test(InetAddress group1, InetAddress group2)
|
|
throws IOException
|
|
{
|
|
try (MulticastSocket mc1 = new MulticastSocket();
|
|
MulticastSocket mc2 = new MulticastSocket(mc1.getLocalPort());
|
|
DatagramSocket ds = new DatagramSocket()) {
|
|
final int port = mc1.getLocalPort();
|
|
out.printf("Using port: %d\n", port);
|
|
|
|
mc1.setSoTimeout(TIMEOUT);
|
|
mc2.setSoTimeout(TIMEOUT);
|
|
int nextId = id;
|
|
byte[] msg = (UUID + Integer.toString(nextId)).getBytes("UTF-8");
|
|
DatagramPacket p = new DatagramPacket(msg, msg.length);
|
|
p.setAddress(group1);
|
|
p.setPort(port);
|
|
|
|
// join groups on all network interfaces
|
|
NetworkConfiguration.probe()
|
|
.ip4MulticastInterfaces(false)
|
|
.forEach((nic) -> {
|
|
try {
|
|
mc1.joinGroup(toSocketAddress(group1), nic);
|
|
out.printf("mc1 joined the MC group on %s: %s\n",
|
|
nic.getDisplayName(), group1);
|
|
mc2.joinGroup(toSocketAddress(group2), nic);
|
|
out.printf("mc2 joined the MC group on %s: %s\n",
|
|
nic.getDisplayName(), group2);
|
|
} catch (IOException io) {
|
|
throw new UncheckedIOException(io);
|
|
}
|
|
});
|
|
|
|
out.printf("Sending datagram to: %s/%d\n", group1, port);
|
|
ds.send(p);
|
|
|
|
// the packet should be received by mc1 only
|
|
receive(mc1, true, nextId);
|
|
receive(mc2, false, 0);
|
|
|
|
nextId = ++id;
|
|
msg = (UUID + Integer.toString(nextId)).getBytes("UTF-8");
|
|
p = new DatagramPacket(msg, msg.length);
|
|
p.setAddress(group2);
|
|
p.setPort(port);
|
|
|
|
out.printf("Sending datagram to: %s/%d\n", group2, port);
|
|
ds.send(p);
|
|
|
|
// the packet should be received by mc2 only
|
|
receive(mc2, true, nextId);
|
|
receive(mc1, false, 0);
|
|
|
|
// leave groups on all network interfaces
|
|
NetworkConfiguration.probe()
|
|
.ip4MulticastInterfaces(false)
|
|
.forEach((nic) -> {
|
|
try {
|
|
mc1.leaveGroup(toSocketAddress(group1), nic);
|
|
out.printf("mc1 left the MC group on %s: %s\n",
|
|
nic.getDisplayName(), group1);
|
|
mc2.leaveGroup(toSocketAddress(group2), nic);
|
|
out.printf("mc2 left the MC group on %s: %s\n",
|
|
nic.getDisplayName(), group2);
|
|
} catch (IOException io) {
|
|
throw new UncheckedIOException(io);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public static void main(String args[]) throws IOException {
|
|
IPSupport.throwSkippedExceptionIfNonOperational();
|
|
String os = System.getProperty("os.name");
|
|
|
|
// Requires IP_MULTICAST_ALL on Linux (new since 2.6.31) so skip
|
|
// on older kernels. Note that we skip on <= version 3 to keep the
|
|
// parsing simple
|
|
if (os.equals("Linux")) {
|
|
String osversion = System.getProperty("os.version");
|
|
String[] vers = osversion.split("\\.", 0);
|
|
int major = Integer.parseInt(vers[0]);
|
|
if (major < 3) {
|
|
System.out.format("Kernel version is %s, test skipped%n", osversion);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// multicast groups used for the test
|
|
InetAddress ip4Group1 = InetAddress.getByName("224.1.1.120");
|
|
InetAddress ip4Group2 = InetAddress.getByName("224.1.1.121");
|
|
|
|
test(ip4Group1, ip4Group2);
|
|
}
|
|
}
|