7026376: (dc) DatagramChannel created without specifying protocol family fails to join IPv4 group
authoralanb
Tue, 15 Mar 2011 13:15:31 +0000
changeset 8788 b98f18278dc4
parent 8787 4b055daf8dd0
child 8789 23f273e43be9
child 8792 cd1dceb2d665
7026376: (dc) DatagramChannel created without specifying protocol family fails to join IPv4 group Reviewed-by: chegar
jdk/make/java/nio/mapfile-linux
jdk/make/java/nio/mapfile-solaris
jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
jdk/src/share/classes/sun/nio/ch/Net.java
jdk/src/solaris/native/sun/nio/ch/Net.c
jdk/src/windows/native/sun/nio/ch/Net.c
jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
--- a/jdk/make/java/nio/mapfile-linux	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/make/java/nio/mapfile-linux	Tue Mar 15 13:15:31 2011 +0000
@@ -95,6 +95,8 @@
 		Java_sun_nio_ch_NativeThread_current;
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
+		Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
+		Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
 		Java_sun_nio_ch_Net_socket0;
 		Java_sun_nio_ch_Net_bind0;
 		Java_sun_nio_ch_Net_connect0;
--- a/jdk/make/java/nio/mapfile-solaris	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/make/java/nio/mapfile-solaris	Tue Mar 15 13:15:31 2011 +0000
@@ -82,6 +82,8 @@
 		Java_sun_nio_ch_NativeThread_current;
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
+		Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0;
+                Java_sun_nio_ch_Net_canJoin6WithIPv4Group0;
 		Java_sun_nio_ch_Net_socket0;
 		Java_sun_nio_ch_Net_bind0;
 		Java_sun_nio_ch_Net_connect0;
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Tue Mar 15 13:15:31 2011 +0000
@@ -755,11 +755,14 @@
             throw new IllegalArgumentException("Group not a multicast address");
 
         // check multicast address is compatible with this socket
-        if (!(group instanceof Inet4Address)) {
-            if (family == StandardProtocolFamily.INET)
-                throw new IllegalArgumentException("Group is not IPv4 address");
-            if (!(group instanceof Inet6Address))
-                throw new IllegalArgumentException("Address type not supported");
+        if (group instanceof Inet4Address) {
+            if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
+                throw new IllegalArgumentException("Group is not IPv4 multicast address");
+        } else if (group instanceof Inet6Address) {
+            if (family != StandardProtocolFamily.INET6)
+                throw new IllegalArgumentException("Group is not IPv6 multicast address");
+        } else {
+            throw new IllegalArgumentException("Address type not supported");
         }
 
         // check source address
@@ -791,7 +794,9 @@
             }
 
             MembershipKeyImpl key;
-            if (family == StandardProtocolFamily.INET6) {
+            if ((family == StandardProtocolFamily.INET6) &&
+                ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
+            {
                 int index = interf.getIndex();
                 if (index == -1)
                     throw new IOException("Network interface cannot be identified");
@@ -861,7 +866,7 @@
                 return;
 
             try {
-                if (family == StandardProtocolFamily.INET6) {
+                if (key instanceof MembershipKeyImpl.Type6) {
                     MembershipKeyImpl.Type6 key6 =
                         (MembershipKeyImpl.Type6)key;
                     Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
@@ -901,7 +906,7 @@
                 throw new IllegalArgumentException("Source address is different type to group");
 
             int n;
-            if (family == StandardProtocolFamily.INET6) {
+            if (key instanceof MembershipKeyImpl.Type6) {
                  MembershipKeyImpl.Type6 key6 =
                     (MembershipKeyImpl.Type6)key;
                 n = Net.block6(fd, key6.groupAddress(), key6.index(),
@@ -931,7 +936,7 @@
                 throw new IllegalStateException("key is no longer valid");
 
             try {
-                if (family == StandardProtocolFamily.INET6) {
+                if (key instanceof MembershipKeyImpl.Type6) {
                     MembershipKeyImpl.Type6 key6 =
                         (MembershipKeyImpl.Type6)key;
                     Net.unblock6(fd, key6.groupAddress(), key6.index(),
--- a/jdk/src/share/classes/sun/nio/ch/Net.java	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java	Tue Mar 15 13:15:31 2011 +0000
@@ -60,6 +60,21 @@
         return isIPv6Available;
     }
 
+    /**
+     * Tells whether IPv6 sockets can join IPv4 multicast groups
+     */
+    static boolean canIPv6SocketJoinIPv4Group() {
+        return canIPv6SocketJoinIPv4Group0();
+    }
+
+    /**
+     * Tells whether {@link #join6} can be used to join an IPv4
+     * multicast group (IPv4 group as IPv4-mapped IPv6 address)
+     */
+    static boolean canJoin6WithIPv4Group() {
+        return canJoin6WithIPv4Group0();
+    }
+
     static InetSocketAddress checkAddress(SocketAddress sa) {
         if (sa == null)
             throw new NullPointerException();
@@ -291,7 +306,11 @@
 
     // -- Socket operations --
 
-    static native boolean isIPv6Available0();
+    private static native boolean isIPv6Available0();
+
+    private static native boolean canIPv6SocketJoinIPv4Group0();
+
+    private static native boolean canJoin6WithIPv4Group0();
 
     static FileDescriptor socket(boolean stream) {
         return socket(UNSPEC, stream);
--- a/jdk/src/solaris/native/sun/nio/ch/Net.c	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/src/solaris/native/sun/nio/ch/Net.c	Tue Mar 15 13:15:31 2011 +0000
@@ -154,6 +154,22 @@
     return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
+{
+    return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
+{
+#ifdef __solaris__
+    return JNI_TRUE;
+#else
+    return JNI_FALSE;
+#endif
+}
+
 JNIEXPORT int JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
                             jboolean stream, jboolean reuse)
--- a/jdk/src/windows/native/sun/nio/ch/Net.c	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/src/windows/native/sun/nio/ch/Net.c	Tue Mar 15 13:15:31 2011 +0000
@@ -100,6 +100,18 @@
     return JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
+{
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
+{
+    return JNI_FALSE;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
                             jboolean stream, jboolean reuse)
--- a/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java	Mon Mar 14 14:49:52 2011 -0700
+++ b/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java	Tue Mar 15 13:15:31 2011 +0000
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 4527345
+ * @bug 4527345 7026376
  * @summary Unit test for DatagramChannel's multicast support
  * @build MulticastSendReceiveTests NetworkConfiguration
  * @run main MulticastSendReceiveTests
@@ -31,12 +31,19 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.*;
 import java.net.*;
+import static java.net.StandardProtocolFamily.*;
 import java.util.*;
 import java.io.IOException;
 
 public class MulticastSendReceiveTests {
 
-    static Random rand = new Random();
+    static final Random rand = new Random();
+
+    static final ProtocolFamily UNSPEC = new ProtocolFamily() {
+        public String name() {
+            return "UNSPEC";
+        }
+    };
 
     /**
      * Send datagram from given local address to given multicast
@@ -130,75 +137,84 @@
     /**
      * Exercise multicast send/receive on given group/interface
      */
-    static void test(NetworkInterface nif, InetAddress group, InetAddress source)
+    static void test(ProtocolFamily family,
+                     NetworkInterface nif,
+                     InetAddress group,
+                     InetAddress source)
         throws IOException
     {
-        ProtocolFamily family = (group instanceof Inet6Address) ?
-            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
-        System.out.format("create channel to %s socket\n", family.name());
-        DatagramChannel dc = DatagramChannel.open(family)
-            .setOption(StandardSocketOption.SO_REUSEADDR, true)
-            .bind(new InetSocketAddress(0));
-
-        // join group
-        System.out.format("join %s @ %s\n", group.getHostAddress(),
-            nif.getName());
-        MembershipKey key = dc.join(group, nif);
+        System.out.format("\nTest DatagramChannel to %s socket\n", family.name());
+        try (DatagramChannel dc = (family == UNSPEC) ?
+                DatagramChannel.open() : DatagramChannel.open(family)) {
+            dc.setOption(StandardSocketOption.SO_REUSEADDR, true)
+              .bind(new InetSocketAddress(0));
 
-        // send message to group
-        int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
-        int id = sendDatagram(source, nif, group, port);
-
-        // receive message and check id matches
-        receiveDatagram(dc, source, id);
+            // join group
+            System.out.format("join %s @ %s\n", group.getHostAddress(),
+                nif.getName());
+            MembershipKey key;
+            try {
+                key = dc.join(group, nif);
+            } catch (IllegalArgumentException iae) {
+                if (family == UNSPEC) {
+                    System.out.println("Not supported");
+                    return;
+                }
+                throw iae;
+            }
 
-        // exclude-mode filtering
-
-        try {
-            System.out.format("block %s\n", source.getHostAddress());
+            // send message to group
+            int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
+            int id = sendDatagram(source, nif, group, port);
 
-            // may throw UOE
-            key.block(source);
-            id = sendDatagram(source, nif, group, port);
-            receiveDatagram(dc, null, id);
+            // receive message and check id matches
+            receiveDatagram(dc, source, id);
+
+            // exclude-mode filtering
+
+            try {
+                System.out.format("block %s\n", source.getHostAddress());
 
-            // unblock source, send message, message should be received
-            System.out.format("unblock %s\n", source.getHostAddress());
-            key.unblock(source);
-            id = sendDatagram(source, nif, group, port);
-            receiveDatagram(dc, source, id);
-        } catch (UnsupportedOperationException x) {
-            System.out.println("Exclude-mode filtering not supported!");
-        }
+                // may throw UOE
+                key.block(source);
+                id = sendDatagram(source, nif, group, port);
+                receiveDatagram(dc, null, id);
 
-        key.drop();
+                // unblock source, send message, message should be received
+                System.out.format("unblock %s\n", source.getHostAddress());
+                key.unblock(source);
+                id = sendDatagram(source, nif, group, port);
+                receiveDatagram(dc, source, id);
+            } catch (UnsupportedOperationException x) {
+                System.out.println("Exclude-mode filtering not supported!");
+            }
 
-        // include-mode filtering
+            key.drop();
+
+            // include-mode filtering
 
-        InetAddress bogus = (group instanceof Inet6Address) ?
-            InetAddress.getByName("fe80::1234") :
-            InetAddress.getByName("1.2.3.4");
-        System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
-            nif.getName(), bogus.getHostAddress());
-        try {
-            // may throw UOE
-            key = dc.join(group, nif, bogus);
-
-            id = sendDatagram(source, nif, group, port);
-            receiveDatagram(dc, null, id);
+            InetAddress bogus = (group instanceof Inet6Address) ?
+                InetAddress.getByName("fe80::1234") :
+                InetAddress.getByName("1.2.3.4");
+            System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
+                nif.getName(), bogus.getHostAddress());
+            try {
+                // may throw UOE
+                key = dc.join(group, nif, bogus);
 
-            System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
-                nif.getName(), source.getHostAddress());
-            key = dc.join(group, nif, source);
+                id = sendDatagram(source, nif, group, port);
+                receiveDatagram(dc, null, id);
+
+                System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
+                    nif.getName(), source.getHostAddress());
+                key = dc.join(group, nif, source);
 
-            id = sendDatagram(source, nif, group, port);
-            receiveDatagram(dc, source, id);
-        } catch (UnsupportedOperationException x) {
-            System.out.println("Include-mode filtering not supported!");
+                id = sendDatagram(source, nif, group, port);
+                receiveDatagram(dc, source, id);
+            } catch (UnsupportedOperationException x) {
+                System.out.println("Include-mode filtering not supported!");
+            }
         }
-
-        // done
-        dc.close();
     }
 
     public static void main(String[] args) throws IOException {
@@ -210,12 +226,14 @@
 
         for (NetworkInterface nif: config.ip4Interfaces()) {
             InetAddress source = config.ip4Addresses(nif).iterator().next();
-            test(nif, ip4Group, source);
+            test(INET,   nif, ip4Group, source);
+            test(UNSPEC, nif, ip4Group, source);
         }
 
         for (NetworkInterface nif: config.ip6Interfaces()) {
             InetAddress source = config.ip6Addresses(nif).iterator().next();
-            test(nif, ip6Group, source);
+            test(INET6,  nif, ip6Group, source);
+            test(UNSPEC, nif, ip6Group, source);
         }
     }
 }