diff --git a/src/java.base/share/classes/java/net/DatagramSocket.java b/src/java.base/share/classes/java/net/DatagramSocket.java index e95b5ce9bc8..195894a57d7 100644 --- a/src/java.base/share/classes/java/net/DatagramSocket.java +++ b/src/java.base/share/classes/java/net/DatagramSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -28,6 +28,7 @@ package java.net; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.channels.DatagramChannel; +import java.nio.channels.MulticastChannel; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Set; @@ -81,11 +82,11 @@ import sun.nio.ch.DefaultSelectorProvider; *
*In addition, the {@code DatagramSocket} class defines methods to {@linkplain + * #joinGroup(SocketAddress, NetworkInterface) join} and {@linkplain + * #leaveGroup(SocketAddress, NetworkInterface) leave} a multicast group, and + * supports multicast options which + * are useful when {@linkplain #joinGroup(SocketAddress, NetworkInterface) joining}, + * {@linkplain #leaveGroup(SocketAddress, NetworkInterface) leaving}, or sending datagrams + * to a multicast group. + * The following multicast options are supported: + *
+ * + *+ * An implementation may also support additional options. + * + * @apiNote Multicasting with DatagramSocket + * + *+ * + * + *
+ *+ * + * + * + *Option Name + *Description + *+ * + *{@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} + *The network interface for Internet Protocol (IP) multicast datagrams + *+ * + *{@link java.net.StandardSocketOptions#IP_MULTICAST_TTL + * IP_MULTICAST_TTL} + *The time-to-live for Internet Protocol (IP) multicast + * datagrams + *+ * + * + *{@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP + * IP_MULTICAST_LOOP} + *Loopback for Internet Protocol (IP) multicast datagrams + *
{@link DatagramChannel} implements the {@link MulticastChannel} interface + * and provides an alternative API for sending and receiving multicast datagrams. + * The {@link MulticastChannel} API supports both {@linkplain + * MulticastChannel#join(InetAddress, NetworkInterface) any-source} and + * {@linkplain MulticastChannel#join(InetAddress, NetworkInterface, InetAddress) + * source-specific} multicast. Consider using {@code DatagramChannel} for + * multicasting. + * + *
{@code DatagramSocket} can be used directly for multicasting. However, + * contrarily to {@link MulticastSocket}, {@code DatagramSocket} doesn't call the + * {@link DatagramSocket#setReuseAddress(boolean)} method to enable the SO_REUSEADDR + * socket option by default. If creating a {@code DatagramSocket} intended to + * later join a multicast group, the caller should consider explicitly enabling + * the SO_REUSEADDR option. + * + *
An instance of {@code DatagramSocket} can be used to send or + * receive multicast datagram packets. It is not necessary to join a multicast + * group in order to send multicast datagrams. Before sending out multicast + * datagram packets however, the default outgoing interface for sending + * multicast datagram should first be configured using + * {@link #setOption(SocketOption, Object) setOption} and + * {@link StandardSocketOptions#IP_MULTICAST_IF}: + * + *
{@code
+ * DatagramSocket sender = new DatagramSocket(new InetSocketAddress(0));
+ * NetworkInterface outgoingIf = NetworkInterface.getByName("en0");
+ * sender.setOption(StandardSocketOptions.IP_MULTICAST_IF, outgoingIf);
+ *
+ * // optionally configure multicast TTL; the TTL defines the scope of a
+ * // multicast datagram, for example, confining it to host local (0) or
+ * // link local (1) etc...
+ * int ttl = ...; // a number betwen 0 and 255
+ * sender.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
+ *
+ * // send a packet to a multicast group
+ * byte[] msgBytes = ...;
+ * InetAddress mcastaddr = InetAddress.getByName("228.5.6.7");
+ * int port = 6789;
+ * InetSocketAddress dest = new InetSocketAddress(mcastaddr, port);
+ * DatagramPacket hi = new DatagramPacket(msgBytes, msgBytes.length, dest);
+ * sender.send(hi);
+ * }
+ *
+ * An instance of {@code DatagramSocket} can also be used to receive + * multicast datagram packets. A {@code DatagramSocket} that is created + * with the intent of receiving multicast datagrams should be created + * unbound. Before binding the socket, {@link #setReuseAddress(boolean) + * setReuseAddress(true)} should be configured: + * + *
{@code
+ * DatagramSocket socket = new DatagramSocket(null); // unbound
+ * socket.setReuseAddress(true); // set reuse address before binding
+ * socket.bind(new InetSocketAddress(6789)); // bind
+ *
+ * // joinGroup 228.5.6.7
+ * InetAddress mcastaddr = InetAddress.getByName("228.5.6.7");
+ * InetSocketAddress group = new InetSocketAddress(mcastaddr, 0);
+ * NetworkInterface netIf = NetworkInterface.getByName("en0");
+ * socket.joinGroup(group, netIf);
+ * byte[] msgBytes = new byte[1024]; // up to 1024 bytes
+ * DatagramPacket packet = new DatagramPacket(msgBytes, msgBytes.length);
+ * socket.receive(packet);
+ * ....
+ * // eventually leave group
+ * socket.leaveGroup(group, netIf);
+ * }
+ *
+ * The multicast implementation is intended to map directly to the native + * multicasting facility. Consequently, the following items should be considered + * when developing an application that receives IP multicast datagrams: + *
In order to join a multicast group, the caller should specify + * the IP address of the multicast group to join, and the local + * {@linkplain NetworkInterface network interface} to receive multicast + * packets from. + *
It is possible to call this method several times to join + * several different multicast groups, or join the same group + * in several different networks. However, if the socket is already a + * member of the group, an {@link IOException} will be thrown. + * + *
If there is a security manager, this method first + * calls its {@code checkMulticast} method with the {@code mcastaddr} + * argument as its argument. + * + * @apiNote The default interface for sending outgoing multicast datagrams + * can be configured with {@link #setOption(SocketOption, Object)} + * with {@link StandardSocketOptions#IP_MULTICAST_IF}. + * + * @param mcastaddr indicates the multicast address to join. + * @param netIf specifies the local interface to receive multicast + * datagram packets, or {@code null}. + * @throws IOException if there is an error joining, or when the address + * is not a multicast address, or the platform does not support + * multicasting + * @throws SecurityException if a security manager exists and its + * {@code checkMulticast} method doesn't allow the join. + * @throws IllegalArgumentException if mcastaddr is {@code null} or is a + * SocketAddress subclass not supported by this socket + * @see SecurityManager#checkMulticast(InetAddress) + * @see DatagramChannel#join(InetAddress, NetworkInterface) + * @see StandardSocketOptions#IP_MULTICAST_IF + * @since 17 + */ + public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) + throws IOException { + delegate().joinGroup(mcastaddr, netIf); + } + + /** + * Leave a multicast group on a specified local interface. + * + *
If there is a security manager, this method first + * calls its {@code checkMulticast} method with the + * {@code mcastaddr} argument as its argument. + * + * @apiNote + * The {@code mcastaddr} and {@code netIf} arguments should identify + * a multicast group that was previously {@linkplain + * #joinGroup(SocketAddress, NetworkInterface) joined} by + * this {@code DatagramSocket}. + *
It is possible to call this method several times to leave
+ * multiple different multicast groups previously joined, or leave
+ * the same group previously joined in multiple different networks.
+ * However, if the socket is not a member of the specified group
+ * in the specified network, an {@link IOException} will be
+ * thrown.
+ *
+ * @param mcastaddr is the multicast address to leave. This should
+ * contain the same IP address than that used for {@linkplain
+ * #joinGroup(SocketAddress, NetworkInterface) joining}
+ * the group.
+ * @param netIf specifies the local interface or {@code null} to defer
+ * to the interface set for outgoing multicast datagrams.
+ * If {@code null}, and no interface has been set, the behaviour
+ * is unspecified: any interface may be selected or the operation
+ * may fail with a {@code SocketException}.
+ * @throws IOException if there is an error leaving or when the address
+ * is not a multicast address.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkMulticast} method doesn't allow the operation.
+ * @throws IllegalArgumentException if mcastaddr is {@code null} or is a
+ * SocketAddress subclass not supported by this socket.
+ * @see SecurityManager#checkMulticast(InetAddress)
+ * @see #joinGroup(SocketAddress, NetworkInterface)
+ * @see StandardSocketOptions#IP_MULTICAST_IF
+ * @since 17
+ */
+ public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+ throws IOException {
+ delegate().leaveGroup(mcastaddr, netIf);
+ }
+
// Temporary solution until JDK-8237352 is addressed
private static final SocketAddress NO_DELEGATE = new SocketAddress() {};
private static final boolean USE_PLAINDATAGRAMSOCKET = usePlainDatagramSocketImpl();
diff --git a/src/java.base/share/classes/java/net/MulticastSocket.java b/src/java.base/share/classes/java/net/MulticastSocket.java
index c1ebaa72ba2..23c534d0abe 100644
--- a/src/java.base/share/classes/java/net/MulticastSocket.java
+++ b/src/java.base/share/classes/java/net/MulticastSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -44,7 +44,7 @@ import java.nio.channels.MulticastChannel;
* with the desired port, then invoking the
* joinGroup(InetAddress groupAddr)
* method:
- *
+ * {@code
* // join a Multicast group and send the group salutations
* ...
* String msg = "Hello";
@@ -65,7 +65,7 @@ import java.nio.channels.MulticastChannel;
* ...
* // OK, I'm done talking - leave the group...
* s.leaveGroup(group, netIf);
- *
+ * }
*
* When one sends a message to a multicast group, all subscribing
* recipients to that host and port receive the message (within the
@@ -86,46 +86,19 @@ import java.nio.channels.MulticastChannel;
* supports the {@link #setOption(SocketOption, Object) setOption}
* and {@link #getOption(SocketOption) getOption} methods to set
* and query socket options.
- * In addition to the socket options supported by
- * {@code DatagramSocket}, a
- * {@code MulticastSocket} supports the following socket options:
- * - * - *+ * The set of supported socket options + * is defined in {@code DatagramSocket}. * Additional (implementation specific) options may also be supported. * - * @apiNote {@link DatagramChannel} implements the {@link MulticastChannel} interface + * @apiNote {@link DatagramSocket} may be used directly for + * sending and receiving multicast datagrams. + * {@link DatagramChannel} implements the {@link MulticastChannel} interface * and provides an alternative API for sending and receiving multicast datagrams. * The {@link MulticastChannel} API supports both {@linkplain * MulticastChannel#join(InetAddress, NetworkInterface) any-source} and * {@linkplain MulticastChannel#join(InetAddress, NetworkInterface, InetAddress) - * source-specific} multicast. + * source-specific} multicast. Consider using {@link DatagramChannel} for + * multicasting. * * @author Pavani Diwanji * @since 1.1 @@ -243,7 +216,7 @@ public class MulticastSocket extends DatagramSocket { * @param ttl the time-to-live * @throws IOException if an I/O exception occurs * while setting the default time-to-live value - * @deprecated use the setTimeToLive method instead, which uses + * @deprecated use the {@link #setTimeToLive(int)} method instead, which uses * int instead of byte as the type for ttl. * @see #getTTL() */ @@ -262,6 +235,10 @@ public class MulticastSocket extends DatagramSocket { * Multicast packets sent with a TTL of {@code 0} are not transmitted * on the network but may be delivered locally. * + * @apiNote + * This method is equivalent to calling {@link #setOption(SocketOption, Object) + * setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl)}. + * * @param ttl * the time-to-live * @@ -270,6 +247,7 @@ public class MulticastSocket extends DatagramSocket { * default time-to-live value * * @see #getTimeToLive() + * @see StandardSocketOptions#IP_MULTICAST_TTL * @since 1.2 */ public void setTimeToLive(int ttl) throws IOException { @@ -283,8 +261,8 @@ public class MulticastSocket extends DatagramSocket { * @throws IOException if an I/O exception occurs * while getting the default time-to-live value * @return the default time-to-live value - * @deprecated use the getTimeToLive method instead, which returns - * an int instead of a byte. + * @deprecated use the {@link #getTimeToLive()} method instead, + * which returns an int instead of a byte. * @see #setTTL(byte) */ @Deprecated @@ -295,10 +273,16 @@ public class MulticastSocket extends DatagramSocket { /** * Get the default time-to-live for multicast packets sent out on * the socket. + * + * @apiNote + * This method is equivalent to calling {@link #getOption(SocketOption) + * getOption(StandardSocketOptions.IP_MULTICAST_TTL)}. + * * @throws IOException if an I/O exception occurs while * getting the default time-to-live value * @return the default time-to-live value * @see #setTimeToLive(int) + * @see StandardSocketOptions#IP_MULTICAST_TTL * @since 1.2 */ public int getTimeToLive() throws IOException { @@ -313,6 +297,11 @@ public class MulticastSocket extends DatagramSocket { * calls its {@code checkMulticast} method with the * {@code mcastaddr} argument as its argument. * + * @apiNote + * Calling this method is equivalent to calling + * {@link #joinGroup(SocketAddress, NetworkInterface) + * joinGroup(new InetSocketAddress(mcastaddr, 0), null)}. + * * @param mcastaddr is the multicast address to join * @throws IOException if there is an error joining, * or when the address is not a multicast address, @@ -337,6 +326,11 @@ public class MulticastSocket extends DatagramSocket { * calls its {@code checkMulticast} method with the * {@code mcastaddr} argument as its argument. * + * @apiNote + * Calling this method is equivalent to calling + * {@link #leaveGroup(SocketAddress, NetworkInterface) + * leaveGroup(new InetSocketAddress(mcastaddr, 0), null)}. + * * @param mcastaddr is the multicast address to leave * @throws IOException if there is an error leaving * or when the address is not a multicast address. @@ -353,65 +347,38 @@ public class MulticastSocket extends DatagramSocket { } /** - * Joins the specified multicast group at the specified interface. - * - *- * - * - *
- *- * - * - * - *Option Name - *Description - *- * - *{@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} - *The network interface for Internet Protocol (IP) multicast datagrams - *- * - *{@link java.net.StandardSocketOptions#IP_MULTICAST_TTL - * IP_MULTICAST_TTL} - *The time-to-live for Internet Protocol (IP) multicast - * datagrams - *- * - * - *{@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP - * IP_MULTICAST_LOOP} - *Loopback for Internet Protocol (IP) multicast datagrams - *
If there is a security manager, this method first - * calls its {@code checkMulticast} method - * with the {@code mcastaddr} argument - * as its argument. - * - * @param mcastaddr is the multicast address to join - * @param netIf specifies the local interface to receive multicast - * datagram packets, or {@code null} to defer to the interface set by - * {@link MulticastSocket#setInterface(InetAddress)} or - * {@link MulticastSocket#setNetworkInterface(NetworkInterface)}. - * If {@code null}, and no interface has been set, the behaviour is - * unspecified: any interface may be selected or the operation may fail - * with a {@code SocketException}. - * @throws IOException if there is an error joining, or when the address - * is not a multicast address, or the platform does not support - * multicasting - * @throws SecurityException if a security manager exists and its - * {@code checkMulticast} method doesn't allow the join. - * @throws IllegalArgumentException if mcastaddr is {@code null} or is a - * SocketAddress subclass not supported by this socket + * {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @see SecurityManager#checkMulticast(InetAddress) * @see DatagramChannel#join(InetAddress, NetworkInterface) - * @since 1.4 + * @see StandardSocketOptions#IP_MULTICAST_IF + * @see #setNetworkInterface(NetworkInterface) + * @see #setInterface(InetAddress) + * @since 1.4 */ + @Override public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - delegate().joinGroup(mcastaddr, netIf); + throws IOException { + super.joinGroup(mcastaddr, netIf); } /** - * Leave a multicast group on a specified local interface. - * - *
If there is a security manager, this method first - * calls its {@code checkMulticast} method with the - * {@code mcastaddr} argument as its argument. - * - * @param mcastaddr is the multicast address to leave - * @param netIf specifies the local interface or {@code null} to defer - * to the interface set by - * {@link MulticastSocket#setInterface(InetAddress)} or - * {@link MulticastSocket#setNetworkInterface(NetworkInterface)}. - * If {@code null}, and no interface has been set, the behaviour - * is unspecified: any interface may be selected or the operation - * may fail with a {@code SocketException}. - * @throws IOException if there is an error leaving or when the address - * is not a multicast address. - * @throws SecurityException if a security manager exists and its - * {@code checkMulticast} method doesn't allow the operation. - * @throws IllegalArgumentException if mcastaddr is {@code null} or is a - * SocketAddress subclass not supported by this socket. + * {@inheritDoc} + * @apiNote {@inheritDoc} + * @throws IOException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @see SecurityManager#checkMulticast(InetAddress) - * @since 1.4 + * @see #joinGroup(SocketAddress, NetworkInterface) + * @since 1.4 */ + @Override public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - delegate().leaveGroup(mcastaddr, netIf); - } + throws IOException { + super.leaveGroup(mcastaddr, netIf); + } /** * Set the multicast network interface used by methods @@ -455,10 +422,15 @@ public class MulticastSocket extends DatagramSocket { * Specify the network interface for outgoing multicast datagrams * sent on this socket. * + * @apiNote + * This method is equivalent to calling {@link #setOption(SocketOption, Object) + * setOption(StandardSocketOptions.IP_MULTICAST_IF, netIf)}. + * * @param netIf the interface * @throws SocketException if there is an error in * the underlying protocol, such as a TCP error. * @see #getNetworkInterface() + * @see StandardSocketOptions#IP_MULTICAST_IF * @since 1.4 */ public void setNetworkInterface(NetworkInterface netIf) @@ -467,7 +439,13 @@ public class MulticastSocket extends DatagramSocket { } /** - * Get the multicast network interface set. + * Get the multicast network interface set for outgoing multicast + * datagrams sent from this socket. + * + * @apiNote + * When an interface is set, this method is equivalent + * to calling {@link #getOption(SocketOption) + * getOption(StandardSocketOptions.IP_MULTICAST_IF)}. * * @throws SocketException if there is an error in * the underlying protocol, such as a TCP error. @@ -475,6 +453,7 @@ public class MulticastSocket extends DatagramSocket { * NetworkInterface is returned when there is no interface set; it has * a single InetAddress to represent any local address. * @see #setNetworkInterface(NetworkInterface) + * @see StandardSocketOptions#IP_MULTICAST_IF * @since 1.4 */ public NetworkInterface getNetworkInterface() throws SocketException { @@ -564,12 +543,12 @@ public class MulticastSocket extends DatagramSocket { * * * @deprecated Use the following code or its equivalent instead: - * ...... - * int ttl = mcastSocket.getTimeToLive(); - * mcastSocket.setTimeToLive(newttl); + *
{@code ......
+ * int ttl = mcastSocket.getOption(StandardSocketOptions.IP_MULTICAST_TTL);
+ * mcastSocket.setOption(StandardSocketOptions.IP_MULTICAST_TTL, newttl);
* mcastSocket.send(p);
- * mcastSocket.setTimeToLive(ttl);
- * ......
+ * mcastSocket.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
+ * ......}
*
* @see DatagramSocket#send
* @see DatagramSocket#receive
diff --git a/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java b/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
index 62a93995b8d..b9a33a6e4c8 100644
--- a/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
+++ b/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -97,10 +97,9 @@ class DefaultDatagramSocketImplFactory
throw new SocketException("can't instantiate DatagramSocketImpl");
}
} else {
- if (!preferIPv4Stack && !isMulticast)
- return new DualStackPlainDatagramSocketImpl(exclusiveBind);
- else
- return new TwoStacksPlainDatagramSocketImpl(exclusiveBind && !isMulticast, isMulticast);
+ // Always use TwoStacksPlainDatagramSocketImpl since we need
+ // to support multicasting at DatagramSocket level
+ return new TwoStacksPlainDatagramSocketImpl(exclusiveBind && !isMulticast, isMulticast);
}
}
}
diff --git a/test/jdk/java/net/DatagramSocket/DatagramSocketExample.java b/test/jdk/java/net/DatagramSocket/DatagramSocketExample.java
new file mode 100644
index 00000000000..2609380a5dd
--- /dev/null
+++ b/test/jdk/java/net/DatagramSocket/DatagramSocketExample.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 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 8237352
+ * @summary Verifies that the examples using DatagramSocket for
+ * sending and receiving multicast datagrams are functional.
+ * See "Multicasting with DatagramSocket" API note in
+ * DatagramSocket.java
+ *
+ * @library /test/lib
+ * @build jdk.test.lib.NetworkConfiguration
+ * jdk.test.lib.net.IPSupport
+ * @run main/othervm DatagramSocketExample
+ * @run main/othervm -Djava.net.preferIPv4Stack=true DatagramSocketExample
+ * @run main/othervm -Djdk.usePlainDatagramSocketImpl=true DatagramSocketExample
+ * @run main/othervm -Djdk.usePlainDatagramSocketImpl=true -Djava.net.preferIPv4Stack=true DatagramSocketExample
+ */
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.ProtocolFamily;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardSocketOptions;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jdk.test.lib.NetworkConfiguration;
+import jdk.test.lib.net.IPSupport;
+
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static java.net.StandardSocketOptions.IP_MULTICAST_IF;
+import static java.net.StandardSocketOptions.IP_MULTICAST_LOOP;
+import static java.net.StandardSocketOptions.IP_MULTICAST_TTL;
+import static java.net.StandardSocketOptions.SO_REUSEADDR;
+
+public class DatagramSocketExample {
+ static final ProtocolFamily UNSPEC = () -> "UNSPEC";
+
+ public static void main(String[] args) throws IOException {
+ IPSupport.throwSkippedExceptionIfNonOperational();
+
+ // IPv4 and IPv6 interfaces that support multicasting
+ NetworkConfiguration config = NetworkConfiguration.probe();
+ List