Hi Don,

The fix has been integrated. See attachment. It should be in next build of JDK 7.

-Edward

Don Coleman wrote:
-Djava.net.preferIPv4Stack=true works fine for IPv4, but my
application needs to send both IPv4 and IPv6.

I'd be interested to see Edward Wang's patch for this issue.

On 6/1/07, Alan Bateman <[EMAIL PROTECTED]> wrote:
Don Coleman wrote:
> I'm have a problem setting TTL when sending Multicast packets to an
> IPv4 address over an IPv6 socket.
>
> Setting the TTL in Java has no effect when sending to an IPv4 address.
> It is always 1.
>
> This is only a problem on Linux, it works fine on OS X, Solaris and
> Windows.
>
> This problem exists with JDK5, but it looks like it's also in the JDK7
> code.
>
> https://openjdk.dev.java.net/source/browse/openjdk/jdk/trunk/j2se/src/solaris/native/java/net/PlainDatagramSocketImpl.c?annotate=237
>
>
> on line 1873 IPV6_MULTICAST_HOPS is set
> for Linux I think we need also need to set IP_MULTICAST_TTL
>
> I've attached sample Java and C code that demonstrates the problem
> here https://bugs.launchpad.net/ubuntu/+bug/112257
>
> Any thoughts if this is a Java problem or a Linux kernel bug?
The bug tracking this one is:
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6250763

At least in older kernels, it wasn't possible to set IPv4 multicast
options on IPv6 sockets (the setsockopt would fail). Edward Wang has
been testing with recent kernels and has results that suggest that
setting the IPv4 options work now. I believe he has a fix/patch in the
works to address this (Edward - can you comment?).

If you need a workaround then run with -Djava.net.preferIPv4Stack=true
so that all sockets are IPv4 (even if the machine has IPv6 enabled).

-Alan.












--- old/src/solaris/native/java/net/PlainDatagramSocketImpl.c   2007-06-13 
16:02:28.072632000 +0800
+++ new/src/solaris/native/java/net/PlainDatagramSocketImpl.c   2007-06-13 
16:02:23.013719000 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2006 Sun Microsystems, Inc.  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
@@ -454,7 +454,7 @@
        rmtaddrP = 0;
     } else {
        packetPort = (*env)->GetIntField(env, packet, dp_portID);
-       if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct 
sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
+        if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, (struct 
sockaddr *)&rmtaddr, &len, JNI_TRUE) != 0) {
          return;
        }
     }
@@ -1137,6 +1137,153 @@
 
 
 /*
+ * Set outgoing multicast interface designated by a NetworkInterface.
+ * Throw exception if failed.
+ */
+static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    static jfieldID ni_addrsID;
+    static jfieldID ia_addressID;
+    struct in_addr in;
+    jobjectArray addrArray;
+    jsize len;
+    jobject addr;
+    int i;
+
+    if (ni_addrsID == NULL) {
+        jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
+        CHECK_NULL(c);
+        ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 
+                                        "[Ljava/net/InetAddress;");
+        CHECK_NULL(ni_addrsID);
+        c = (*env)->FindClass(env,"java/net/InetAddress");
+        CHECK_NULL(c);
+        ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
+        CHECK_NULL(ia_addressID);
+    }
+
+    addrArray = (*env)->GetObjectField(env, value, ni_addrsID);
+    len = (*env)->GetArrayLength(env, addrArray);
+
+    /*
+     * Check that there is at least one address bound to this
+     * interface.
+     */
+    if (len < 1) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+            "bad argument for IP_MULTICAST_IF2: No IP addresses bound to 
interface");
+        return;
+    }
+
+    /*
+     * We need an ipv4 address here
+     */
+    for (i = 0; i < len; i++) {
+        addr = (*env)->GetObjectArrayElement(env, addrArray, i);
+        if ((*env)->GetIntField(env, addr, ia_familyID) == IPv4) {
+            in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
+            break;
+        }
+    }
+
+    if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+                       (const char*)&in, sizeof(in)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                       "Error setting socket option");
+    }
+}
+
+/*
+ * Set outgoing multicast interface designated by a NetworkInterface.
+ * Throw exception if failed.
+ */
+static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    static jfieldID ni_indexID;
+    int index;
+
+    if (ni_indexID == NULL) {
+        jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
+        CHECK_NULL(c);
+        ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
+        CHECK_NULL(ni_indexID);
+    }
+    index = (*env)->GetIntField(env, value, ni_indexID);
+
+    if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+                       (const char*)&index, sizeof(index)) < 0) {
+        if (errno == EINVAL && index > 0) {
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                "IPV6_MULTICAST_IF failed (interface has IPv4 "
+                "address only?)");
+        } else {
+            NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                           "Error setting socket option");
+        }
+        return;
+    }
+
+#ifdef __linux__
+    /*
+     * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket
+     * option so record index for later retrival.
+     */
+    if (isOldKernel) {
+        (*env)->SetIntField(env, this, pdsi_multicastInterfaceID, 
+                            (jint)index);
+    }
+#endif
+}
+
+/*
+ * Set outgoing multicast interface designated by an InetAddress.
+ * Throw exception if failed.
+ */
+static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    static jfieldID ia_addressID;
+    struct in_addr in;
+
+    if (ia_addressID == NULL) {
+        jclass c = (*env)->FindClass(env,"java/net/InetAddress");
+        CHECK_NULL(c);
+        ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
+        CHECK_NULL(ia_addressID);
+    }
+
+    in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );
+
+    if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+                       (const char*)&in, sizeof(in)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                         "Error setting socket option");
+    }
+}
+
+/*
+ * Set outgoing multicast interface designated by an InetAddress.
+ * Throw exception if failed.
+ */
+static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    static jclass ni_class;
+    if (ni_class == NULL) {
+        jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
+        CHECK_NULL(c);
+        ni_class = (*env)->NewGlobalRef(env, c);
+        CHECK_NULL(ni_class);
+    }
+
+    value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, 
value);
+    if (value == NULL) {
+        if (!(*env)->ExceptionOccurred(env)) {
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                 "bad argument for IP_MULTICAST_IF"
+                 ": address not bound to any interface");
+        }
+        return;
+    }
+
+    mcast_set_if_by_if_v6(env, this, fd, value);
+}
+
+/*
  * Sets the multicast interface. 
  *
  * SocketOptions.IP_MULTICAST_IF :-
@@ -1169,147 +1316,117 @@
     if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
        /*
         * value is an InetAddress.
-        * On IPv4 system use IP_MULTICAST_IF socket option
-        * On IPv6 system get the NetworkInterface that this IP
-        * address is bound too and use the IPV6_MULTICAST_IF 
-        * option instead of IP_MULTICAST_IF
         */
-#ifdef AF_INET6
-       if (ipv6_available()) {
-           static jclass ni_class;
-           if (ni_class == NULL) {
-               jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
-               CHECK_NULL(c);
-               ni_class = (*env)->NewGlobalRef(env, c);
-               CHECK_NULL(ni_class);
-           }
-
-           value = Java_java_net_NetworkInterface_getByInetAddress0(env, 
ni_class, value);
-           if (value == NULL) {
-               if (!(*env)->ExceptionOccurred(env)) {
-                   JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "bad argument for IP_MULTICAST_IF"
-                        ": address not bound to any interface");
-               }
-               return;
-           }
-           opt = java_net_SocketOptions_IP_MULTICAST_IF2;
-       } else
-#endif /* AF_INET6 */
-       {
-           static jfieldID ia_addressID;
-           struct in_addr in;
-
-           if (ia_addressID == NULL) {
-               jclass c = (*env)->FindClass(env,"java/net/InetAddress");
-               CHECK_NULL(c);
-               ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
-               CHECK_NULL(ia_addressID);
-           }
-           
-            in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );
-
-            if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
-                               (const char*)&in, sizeof(in)) < 0) {
-                NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG 
"SocketException",
-                                 "Error setting socket option");
-           }
-           return;
-       }
+#ifdef __solaris__
+        if (ipv6_available()) {
+            mcast_set_if_by_addr_v6(env, this, fd, value);
+        } else {
+            mcast_set_if_by_addr_v4(env, this, fd, value);
+        }
+#endif
+#ifdef __linux__
+        mcast_set_if_by_addr_v4(env, this, fd, value);
+        if (ipv6_available()) {
+            mcast_set_if_by_addr_v6(env, this, fd, value);
+        }
+#endif
     }
 
     if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
        /*
         * value is a NetworkInterface.
-        * On IPv6 system get the index of the interface and use the
-         * IPV6_MULTICAST_IF socket option
-        * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
-         * option.
         */
-#ifdef AF_INET6
+#ifdef __solaris__
         if (ipv6_available()) {
-           static jfieldID ni_indexID;
-           int index;
-
-           if (ni_indexID == NULL) {
-               jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
-               CHECK_NULL(c);
-               ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
-               CHECK_NULL(ni_indexID);
-           }
-            index = (*env)->GetIntField(env, value, ni_indexID);
-
-            if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
-                              (const char*)&index, sizeof(index)) < 0) {
-               if (errno == EINVAL && index > 0) {
-                   JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                       "IPV6_MULTICAST_IF failed (interface has IPv4 "
-                       "address only?)");
-               } else {
-                   NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG 
"SocketException",
-                                   "Error setting socket option");
-               }
-               return;
-           }
+            mcast_set_if_by_if_v6(env, this, fd, value);
+        } else {
+            mcast_set_if_by_if_v4(env, this, fd, value);
+        }
+#endif
 #ifdef __linux__
-           /*
-            * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket
-            * option so record index for later retrival.
-            */
-           if (isOldKernel) {
-               (*env)->SetIntField(env, this, pdsi_multicastInterfaceID, 
-                                   (jint)index);
-           }
+        mcast_set_if_by_if_v4(env, this, fd, value);
+        if (ipv6_available()) {
+            mcast_set_if_by_if_v6(env, this, fd, value);
+        }
 #endif
-           return;
-        } else
-#endif /* AF_INET6 */
-        {
-           static jfieldID ni_addrsID;
-           static jfieldID ia_addressID;
-           struct in_addr in;
-           jobjectArray addrArray;
-           jsize len;
-           jobject addr;
-
-           if (ni_addrsID == NULL) {
-               jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
-               CHECK_NULL(c);
-               ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 
-                                               "[Ljava/net/InetAddress;");
-               CHECK_NULL(ni_addrsID);
-               c = (*env)->FindClass(env,"java/net/InetAddress");
-               CHECK_NULL(c);
-                ia_addressID = (*env)->GetFieldID(env, c, "address", "I");
-               CHECK_NULL(ia_addressID);
-           }
+    }
+}
 
-           addrArray = (*env)->GetObjectField(env, value, ni_addrsID);
-           len = (*env)->GetArrayLength(env, addrArray);
+/*
+ * Enable/disable local loopback of multicast datagrams.
+ */
+static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    jclass cls;
+    jfieldID fid;
+    jboolean on;
+    char loopback;
+
+    cls = (*env)->FindClass(env, "java/lang/Boolean");
+    CHECK_NULL(cls);
+    fid =  (*env)->GetFieldID(env, cls, "value", "Z");
+    CHECK_NULL(fid);
 
-           /*
-            * Check that there is at least one address bound to this
-            * interface.
-            */
-           if (len < 1) {
-               JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                   "bad argument for IP_MULTICAST_IF2: No IP addresses bound 
to interface");
-               return;
-           }
-          
-           addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
-           in.s_addr = htonl((*env)->GetIntField(env, addr, ia_addressID));
+    on = (*env)->GetBooleanField(env, value, fid);
+    loopback = (!on ? 1 : 0);
 
-           if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
-                              (const char*)&in, sizeof(in)) < 0) {
-               NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG 
"SocketException",
-                               "Error setting socket option");
-           }
-           return;
-        } 
+    if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void 
*)&loopback, sizeof(char)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 
"Error setting socket option");
+       return;
+    }
+}
+
+/*
+ * Enable/disable local loopback of multicast datagrams.
+ */
+static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject 
value) {
+    jclass cls;
+    jfieldID fid;
+    jboolean on;
+    int loopback;
+
+    cls = (*env)->FindClass(env, "java/lang/Boolean");
+    CHECK_NULL(cls);
+    fid =  (*env)->GetFieldID(env, cls, "value", "Z");
+    CHECK_NULL(fid);
+
+    on = (*env)->GetBooleanField(env, value, fid);
+    loopback = (!on ? 1 : 0);
+
+    if (NET_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void 
*)&loopback, sizeof(int)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 
"Error setting socket option");
+       return;
     }
+
+#ifdef __linux__
+    /*
+     * Can't query IPV6_MULTICAST_LOOP on Linux 2.2 kernel so
+     * store it in impl so that we can simulate getsockopt.
+     */
+    if (isOldKernel) {
+        (*env)->SetBooleanField(env, this, pdsi_loopbackID, on);
+    }
+#endif
 }
 
+/*
+ * Sets the multicast loopback mode.
+ */
+static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
+                                 jint opt, jobject value) {
+#ifdef __solaris__
+    if (ipv6_available()) {
+        mcast_set_loop_v6(env, this, fd, value);
+    } else {
+        mcast_set_loop_v4(env, this, fd, value);
+    }
+#endif
+#ifdef __linux__
+    mcast_set_loop_v4(env, this, fd, value);
+    if (ipv6_available()) {
+        mcast_set_loop_v6(env, this, fd, value);
+    } 
+#endif
+}
 
 /*
  * Class:     java_net_PlainDatagramSocketImpl
@@ -1355,6 +1472,14 @@
        setMulticastInterface(env, this, fd, opt, value);
        return;
     }
+    
+    /*
+     * Setting the multicast loopback mode handled separately
+     */
+    if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
+        setMulticastLoopbackMode(env, this, fd, opt, value);
+        return;
+    }
 
     /*
      * Map the Java level socket option to the platform specific
@@ -1385,7 +1510,6 @@
 
        case java_net_SocketOptions_SO_REUSEADDR:
        case java_net_SocketOptions_SO_BROADCAST:
-       case java_net_SocketOptions_IP_MULTICAST_LOOP:
            {
                jclass cls;
                jfieldID fid;
@@ -1397,30 +1521,12 @@
                CHECK_NULL(fid);
 
                on = (*env)->GetBooleanField(env, value, fid);
-               if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
-
-                   /*
-                    * IP_MULTICAST_LOOP may be mapped to IPPROTO (arg
-                    * type 'char') or IPPROTO_V6 (arg type 'int').
-                    *
-                    * In addition setLoopbackMode(true) disables 
-                    * IP_MULTICAST_LOOP - doesn't enable it.
-                    */
-                   if (level == IPPROTO_IP) {
-                       optval.c = (!on ? 1 : 0);
-                       optlen = sizeof(optval.c);
-                   } else {
-                       optval.i = (!on ? 1 : 0);
-                       optlen = sizeof(optval.i);
-                   }
-
-               } else {
-                   /* SO_REUSEADDR or SO_BROADCAST */
-                   optval.i = (on ? 1 : 0);
-                   optlen = sizeof(optval.i);
-               }
 
-               break;
+                /* SO_REUSEADDR or SO_BROADCAST */
+                optval.i = (on ? 1 : 0);
+                optlen = sizeof(optval.i);
+                
+                break;
            }
 
        default :
@@ -1434,19 +1540,6 @@
         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", 
"Error setting socket option");
        return;
     }
-
-    /*
-     * Can't query IPV6_MULTICAST_LOOP on Linux 2.2 kernel so
-     * store it in impl so that we can simulate getsockopt.
-     */
-#if defined(__linux__) && defined(AF_INET6)
-    if (isOldKernel && 
-       level == IPPROTO_IPV6 && optname == IPV6_MULTICAST_LOOP) {
-
-       (*env)->SetBooleanField(env, this, pdsi_loopbackID,
-                                (optval.c ? JNI_FALSE :JNI_TRUE));
-    } 
-#endif
 }
 
 
@@ -1844,6 +1937,30 @@
 }
 
 /*
+ * Set TTL for a socket. Throw exception if failed.
+ */
+static void setTTL(JNIEnv *env, int fd, jint ttl) {
+    char ittl = (char)ttl;
+    if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
+                       sizeof(ittl)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                       "Error setting socket option");
+    }
+}
+
+/*
+ * Set hops limit for a socket. Throw exception if failed.
+ */
+static void setHopLimit(JNIEnv *env, int fd, jint ttl) {
+    int ittl = (int)ttl;
+    if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+                       (char*)&ittl, sizeof(ittl)) < 0) {
+        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                       "Error setting socket option");
+    }
+}
+
+/*
  * Class:     java_net_PlainDatagramSocketImpl
  * Method:    setTTL
  * Signature: (B)V
@@ -1864,31 +1981,22 @@
        fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
     }
     /* setsockopt to be correct ttl */
-#ifdef AF_INET6
+#ifdef __solaris__
     if (ipv6_available()) {
-       int ittl = (int)ttl;
-       if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
-                          (char*)&ittl, sizeof(ittl)) < 0) {
-           NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                           "Error setting socket option");
-           return;
-       }
+        setHopLimit(env, fd, ttl);
+    } else {
+        setTTL(env, fd, ttl);
+    }
+#endif
 #ifdef __linux__
-       if (isOldKernel) {
-           (*env)->SetIntField(env, this, pdsi_ttlID, ttl);
-       }
+    setTTL(env, fd, ttl);
+    if (ipv6_available()) {
+        setHopLimit(env, fd, ttl);
+        if (isOldKernel) {
+            (*env)->SetIntField(env, this, pdsi_ttlID, ttl);
+        }
+    }
 #endif
-
-    } else 
-#endif /* AF_INET6 */
-       {
-           char ittl = (char)ttl;
-           if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
-                              sizeof(ittl)) < 0) {
-               NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG 
"SocketException",
-                               "Error setting socket option");
-           }
-       }
 }
 
 /*
--- old/src/solaris/native/java/net/Inet6AddressImpl.c  2007-06-13 
16:02:30.528265000 +0800
+++ new/src/solaris/native/java/net/Inet6AddressImpl.c  2007-06-13 
16:02:28.776611000 +0800
@@ -343,7 +343,7 @@
                                           (jbyte *)&(((struct 
sockaddr_in6*)iterator->ai_addr)->sin6_addr));
 #ifdef __linux__
                if (!kernelIsV22()) {
-                 scope = ((struct 
sockaddr_in6_ext*)iterator->ai_addr)->sin6_scope_id;
+                 scope = ((struct 
sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
                }
 #else
                scope = ((struct 
sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
@@ -558,10 +558,6 @@
     struct sockaddr_in6 him6;
     struct sockaddr_in6 inf6;
     struct sockaddr_in6* netif = NULL;
-#ifdef __linux__
-    struct sockaddr_in6_ext *him6_ext = (struct sockaddr_in6_ext *)&him6;
-    struct sockaddr_in6_ext *if6_ext = NULL;
-#endif
     int len = 0;
     int connect_rv = -1;
 
@@ -590,10 +586,10 @@
     him6.sin6_family = AF_INET6; 
 #ifdef __linux__
     if (scope > 0)
-      him6_ext->sin6_scope_id = scope;
+      him6.sin6_scope_id = scope;
     else
-      him6_ext->sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
-    len = sizeof(struct sockaddr_in6_ext);
+      him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
+    len = sizeof(struct sockaddr_in6);
 #else
     if (scope > 0)
       him6.sin6_scope_id = scope;
@@ -609,12 +605,7 @@
       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
       inf6.sin6_family = AF_INET6; 
-#ifdef __linux__
-      if6_ext = (struct sockaddr_in6_ext *)&inf6;
-      if6_ext->sin6_scope_id = if_scope;
-#else
       inf6.sin6_scope_id = if_scope;
-#endif
       netif = &inf6;
     }
     /*
--- old/src/solaris/native/java/net/NetworkInterface.c  2007-06-13 
16:02:32.877763000 +0800
+++ new/src/solaris/native/java/net/NetworkInterface.c  2007-06-13 
16:02:30.986492000 +0800
@@ -483,7 +483,7 @@
                     (jbyte *)&(((struct 
sockaddr_in6*)addrP->addr)->sin6_addr));
 #ifdef __linux__
                if (!kernelIsV22()) {
-                   scope = ((struct 
sockaddr_in6_ext*)addrP->addr)->sin6_scope_id;
+                   scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
                }
 #else
                scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
@@ -817,7 +817,7 @@
                   &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
             struct netif *ifs_ptr = NULL;
             struct netif *last_ptr = NULL;
-            struct sockaddr_in6_ext addr;
+            struct sockaddr_in6 addr;
 
            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
@@ -830,7 +830,7 @@
 
            ifs = addif(env, ifs, devname, if_idx, AF_INET6,
                        (struct sockaddr *)&addr, 
-                       sizeof(struct sockaddr_in6_ext), plen);
+                       sizeof(struct sockaddr_in6), plen);
 
            /*
              * If an exception occurred then return the list as is.
--- old/src/solaris/native/java/net/net_util_md.c       2007-06-13 
16:02:35.108376000 +0800
+++ new/src/solaris/native/java/net/net_util_md.c       2007-06-13 
16:02:33.363197000 +0800
@@ -146,7 +146,7 @@
 }
 
 int getScopeID (struct sockaddr *him) {
-    struct sockaddr_in6_ext *hext = (struct sockaddr_in6_ext *)him;
+    struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
     if (kernelIsV22()) {
        return 0;
     }
@@ -154,7 +154,7 @@
 }
 
 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
-    struct sockaddr_in6_ext *hext = (struct sockaddr_in6_ext *)him;
+    struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
     if (kernelIsV22()) {
        return 1;       /* scope is ignored for comparison in 2.2 kernel */
     }
@@ -747,11 +747,11 @@
             */
 
            if (!old_kernel) {
-               struct sockaddr_in6_ext *him6_ext = 
-                       (struct sockaddr_in6_ext *)him;
-               him6_ext->sin6_scope_id = cached_scope_id != 0 ?
+               struct sockaddr_in6 *him6 = 
+                       (struct sockaddr_in6 *)him;
+               him6->sin6_scope_id = cached_scope_id != 0 ?
                                            cached_scope_id    : scope_id; 
-               *len = sizeof(struct sockaddr_in6_ext);
+               *len = sizeof(struct sockaddr_in6);
            }
        }
 #else
--- old/src/solaris/native/java/net/net_util_md.h       2007-06-13 
16:02:37.112779000 +0800
+++ new/src/solaris/native/java/net/net_util_md.h       2007-06-13 
16:02:35.722665000 +0800
@@ -36,20 +36,6 @@
 #include <sys/poll.h>
 #endif
 
-/*
- * Linux header files define sockaddr_in6 incorrectly (missing the
- * sin6_scope_id field) so we use our own definition.
- */ 
-#ifdef __linux__
-struct sockaddr_in6_ext { 
-        unsigned short int      sin6_family; 
-        unsigned short int      sin6_port;
-        unsigned int            sin6_flowinfo;
-        struct in6_addr         sin6_addr;
-        unsigned int            sin6_scope_id;
-};
-#endif
-
 
 #ifdef __linux__
 extern int NET_Timeout(int s, long timeout);
@@ -133,18 +119,10 @@
 
 #ifdef AF_INET6
 
-#ifdef __linux__
-#define SOCKADDR       union { \
-                            struct sockaddr_in him4; \
-                            struct sockaddr_in6 him6; \
-                           struct sockaddr_in6_ext him6_ext; \
-                        } 
-#else 
 #define SOCKADDR        union { \
                             struct sockaddr_in him4; \
                             struct sockaddr_in6 him6; \
                        } 
-#endif
 
 #define SOCKADDR_LEN   (ipv6_available() ? sizeof(SOCKADDR) : \
                          sizeof(struct sockaddr_in))
--- /dev/null   2007-06-13 16:02:39.000000000 +0800
+++ new/test/java/net/ipv6tests/BadIPv6Addresses.java   2007-06-13 
16:02:37.572946000 +0800
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test 07/06/12 
+ * @bug 4742177
+ * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux 
& USAGI code
+ */
+import java.net.*;
+import java.util.*;
+
+
+public class BadIPv6Addresses {
+    public static void main(String[] args) throws Exception {
+        String[] badAddresses = new String[] {
+            "0:1:2:3:4:5:6:7:8",        // too many :
+            "0:1:2:3:4:5:6",            // not enough :
+            "0:1:2:3:4:5:6:x",          // bad digits
+            "0:1:2:3:4:5:6::7",         // adjacent :
+            "0:1:2:3:4:5:6:789abcdef",  // too many digits
+            "0:1:2:3::x",               // compressed, bad digits
+            "0:1:2:::3",                // compressed, too many adjacent :
+            "0:1:2:3::abcde",           // compressed, too many digits
+            "0:1",                      // compressed, not enough :
+            "0:0:0:0:0:x:10.0.0.1",     // with embeded ipv4, bad ipv6 digits
+            "0:0:0:0:0:0:10.0.0.x",     // with embeded ipv4, bad ipv4 digits
+            "0:0:0:0:0::0:10.0.0.1",    // with embeded ipv4, adjacent :
+            "0:0:0:0:0:fffff:10.0.0.1", // with embeded ipv4, too many ipv6 
digits
+            "0:0:0:0:0:0:0:10.0.0.1",   // with embeded ipv4, too many :
+            "0:0:0:0:0:10.0.0.1",       // with embeded ipv4, not enough :
+            "0:0:0:0:0:0:10.0.0.0.1",   // with embeded ipv4, too many .
+            "0:0:0:0:0:0:10.0.1",       // with embeded ipv4, not enough .
+            "0:0:0:0:0:0:10..0.0.1",    // with embeded ipv4, adjacent .
+            "::fffx:192.168.0.1",       // with compressed ipv4, bad ipv6 
digits
+            "::ffff:192.168.0.x",       // with compressed ipv4, bad ipv4 
digits
+            ":::ffff:192.168.0.1",      // with compressed ipv4, too many 
adjacent :
+            "::fffff:192.168.0.1",      // with compressed ipv4, too many ipv6 
digits
+            "::ffff:1923.168.0.1",      // with compressed ipv4, too many ipv4 
digits
+            ":ffff:192.168.0.1",        // with compressed ipv4, not enough :
+            "::ffff:192.168.0.1.2",     // with compressed ipv4, too many .
+            "::ffff:192.168.0",         // with compressed ipv4, not enough .
+            "::ffff:192.168..0.1"       // with compressed ipv4, adjacent .
+        };
+        
+        List<String> failedAddrs = new ArrayList<String>();
+        for (String addrStr : badAddresses) {
+            try {
+                InetAddress addr = InetAddress.getByName(addrStr);
+                
+                // it is an error if no exception
+                failedAddrs.add(addrStr);
+            } catch (UnknownHostException e) {
+                // expected
+            }
+        }
+        
+        if (failedAddrs.size() > 0) {
+            System.out.println("We should reject following ipv6 addresses, but 
we didn't:");
+            for (String addr : failedAddrs) {
+                System.out.println("\t" + addr);
+            }
+            throw new RuntimeException("Test failed.");
+        }
+    }
+}
--- /dev/null   2007-06-13 16:02:41.000000000 +0800
+++ new/test/java/net/MulticastSocket/NoLoopbackPackets.java    2007-06-13 
16:02:40.052513000 +0800
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test 07/06/12 
+ * @bug 4742177
+ * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux 
& USAGI code
+ */
+import java.util.*;
+import java.net.*;
+
+
+public class NoLoopbackPackets {
+    private static int PORT = 9001;
+    private static String osname;
+    
+    static boolean isWindows() {
+        if (osname == null)
+            osname = System.getProperty("os.name");
+       return osname.contains("Windows");
+    }
+
+    private static boolean hasIPv6() throws Exception {
+        List<NetworkInterface> nics = Collections.list(
+                                        
NetworkInterface.getNetworkInterfaces());
+        for (NetworkInterface nic : nics) {
+            if (!nic.isLoopback()) {
+                List<InetAddress> addrs = 
Collections.list(nic.getInetAddresses());
+                for (InetAddress addr : addrs) {
+                    if (addr instanceof Inet6Address) {
+                        return true;
+                    }
+                }
+            }
+        }
+        
+        return false;
+    }
+    
+    public static void main(String[] args) throws Exception {
+        if (isWindows()) {
+            System.out.println("The test only run on non-Windows OS. Bye.");
+            return;
+        }
+        
+        if (!hasIPv6()) {
+            System.out.println("No IPv6 available. Bye.");
+            return;
+        }
+
+        // we will send packets to three multicast groups :-
+        // 224.1.1.1, ::ffff:224.1.1.2, and ff02::1:1
+        //
+        List<SocketAddress> groups = new ArrayList<SocketAddress>();
+        groups.add(new InetSocketAddress(InetAddress.getByName("224.1.1.1"), 
PORT));
+        groups.add(new 
InetSocketAddress(InetAddress.getByName("::ffff:224.1.1.2"), PORT));
+        groups.add(new InetSocketAddress(InetAddress.getByName("ff02::1:1"), 
PORT));
+
+        Thread sender = new Thread(new Sender(groups));
+        sender.setDaemon(true); // we want sender to stop when main thread 
exits
+        sender.start();
+
+        // Now try to receive multicast packets. we should not see any of them
+        // since we disable loopback mode.
+        //
+        MulticastSocket msock = new MulticastSocket(PORT);
+        msock.setSoTimeout(5000);       // 5 seconds
+
+        byte[] buf = new byte[1024];
+        DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
+        List<SocketAddress> failedGroups = new ArrayList<SocketAddress>();
+        for (SocketAddress group : groups) {
+            msock.joinGroup(group, null);
+
+            try {
+                msock.receive(packet);
+
+                // it is an error if we receive something
+                failedGroups.add(group);
+            } catch (SocketTimeoutException e) {
+                // we expect this
+            }
+
+            msock.leaveGroup(group, null);
+        }
+
+        if (failedGroups.size() > 0) {
+            System.out.println("We should not receive anything from following 
groups, but we did:");
+            for (SocketAddress group : failedGroups)
+                System.out.println(group);
+            throw new RuntimeException("test failed.");
+        }
+    }
+}
+
+class Sender implements Runnable {
+    private List<SocketAddress> sendToGroups;
+
+    public Sender(List<SocketAddress> groups) {
+        sendToGroups = groups;
+    }
+
+    public void run() {
+        byte[] buf = "hello world".getBytes();
+        List<DatagramPacket> packets = new ArrayList<DatagramPacket>();
+
+        try {
+            for (SocketAddress group : sendToGroups) {
+                DatagramPacket packet = new DatagramPacket(buf, buf.length, 
group);
+                packets.add(packet);
+            }
+
+            MulticastSocket msock = new MulticastSocket();
+            msock.setLoopbackMode(true);    // disable loopback mode
+            for (;;) {
+                for (DatagramPacket packet : packets) {
+                    msock.send(packet);
+                }
+
+                Thread.currentThread().sleep(1000);     // 1 second
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null   2007-06-13 16:02:41.000000000 +0800
+++ new/test/java/net/MulticastSocket/SetOutgoingIf.java        2007-06-13 
16:02:41.346246000 +0800
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test 07/06/12 
+ * @bug 4742177
+ * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux 
& USAGI code
+ */
+import java.net.*;
+import java.util.concurrent.*;
+import java.util.*;
+
+
+public class SetOutgoingIf {
+    private static int PORT = 9001;
+    private static String osname;
+    
+    static boolean isWindows() {
+        if (osname == null)
+            osname = System.getProperty("os.name");
+       return osname.contains("Windows");
+    }
+    
+    private static boolean hasIPv6() throws Exception {
+        List<NetworkInterface> nics = Collections.list(
+                                        
NetworkInterface.getNetworkInterfaces());
+        for (NetworkInterface nic : nics) {
+            List<InetAddress> addrs = Collections.list(nic.getInetAddresses());
+            for (InetAddress addr : addrs) {
+                if (addr instanceof Inet6Address)
+                    return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    public static void main(String[] args) throws Exception {
+        if (isWindows()) {
+            System.out.println("The test only run on non-Windows OS. Bye.");
+            return;
+        }
+
+        if (!hasIPv6()) {
+            System.out.println("No IPv6 available. Bye.");
+            return;
+        }
+        
+        // We need 2 or more network interfaces to run the test
+        //
+        List<NetworkInterface> nics = new ArrayList<NetworkInterface>();
+        for (NetworkInterface nic : 
Collections.list(NetworkInterface.getNetworkInterfaces())) {
+            if (!nic.isLoopback())
+                nics.add(nic);
+        }
+        if (nics.size() <= 1) {
+            System.out.println("Need 2 or more network interfaces to run. 
Bye.");
+            return;
+        }
+
+        // We will send packets to one ipv4, one ipv4-mapped, and one ipv6
+        // multicast group using each network interface :-
+        //      224.1.1.1        --|
+        //      ::ffff:224.1.1.2 -----> using network interface #1
+        //      ff02::1:1        --|
+        //      224.1.2.1        --|
+        //      ::ffff:224.1.2.2 -----> using network interface #2
+        //      ff02::1:2        --|
+        // and so on.
+        //
+        List<InetAddress> groups = new ArrayList<InetAddress>();
+        for (int i = 0; i < nics.size(); i++) {
+            InetAddress groupv4 = InetAddress.getByName("224.1." + (i+1) + 
".1");
+            InetAddress groupv4mapped = InetAddress.getByName("::ffff:224.1." 
+ (i+1) + ".2");
+            InetAddress groupv6 = InetAddress.getByName("ff02::1:" + (i+1));
+            groups.add(groupv4);
+            groups.add(groupv4mapped);
+            groups.add(groupv6);
+            
+            // use a separated thread to send to those 3 groups
+            Thread sender = new Thread(new Sender(nics.get(i), groupv4, 
groupv4mapped, groupv6, PORT));
+            sender.setDaemon(true); // we want sender to stop when main thread 
exits
+            sender.start();
+        }
+        
+        // try to receive on each group, then check if the packet comes
+        // from the expected network interface
+        //
+        byte[] buf = new byte[1024];
+        for (InetAddress group : groups) {
+        MulticastSocket mcastsock = new MulticastSocket(PORT);
+        mcastsock.setSoTimeout(5000);   // 5 second
+            DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
+            
+            mcastsock.joinGroup(new InetSocketAddress(group, PORT), 
nics.get(groups.indexOf(group) / 3));
+            
+            try {
+                mcastsock.receive(packet);
+            } catch (Exception e) {
+                // test failed if any exception
+                throw new RuntimeException(e);
+            }
+            
+            // now check which network interface this packet comes from
+            NetworkInterface from = 
NetworkInterface.getByInetAddress(packet.getAddress());
+            NetworkInterface shouldbe = nics.get(groups.indexOf(group) / 3);
+            if (!from.equals(shouldbe)) {
+                System.out.println("Packets on group "
+                                    + group + " should come from "
+                                    + shouldbe.getName() + ", but came from "
+                                    + from.getName());
+                //throw new RuntimeException("Test failed.");
+            }
+            
+            mcastsock.leaveGroup(new InetSocketAddress(group, PORT), 
nics.get(groups.indexOf(group) / 3));
+        }
+    }
+}
+
+class Sender implements Runnable {
+    private NetworkInterface nic;
+    private InetAddress group1;
+    private InetAddress group2;
+    private InetAddress group3;
+    private int port;
+    
+    public Sender(NetworkInterface nic,
+                    InetAddress groupv4, InetAddress groupv4mapped, 
InetAddress groupv6,
+                    int port) {
+        this.nic = nic;
+        group1 = groupv4;
+        group2 = groupv4mapped;
+        group3 = groupv6;
+        this.port = port;
+    }
+    
+    public void run() {
+        try {
+            MulticastSocket mcastsock = new MulticastSocket();
+            mcastsock.setNetworkInterface(nic);
+            
+            byte[] buf = "hello world".getBytes();
+            DatagramPacket packet1 = new DatagramPacket(buf, buf.length,
+                                        new InetSocketAddress(group1, port));
+            DatagramPacket packet2 = new DatagramPacket(buf, buf.length,
+                                        new InetSocketAddress(group2, port));
+            DatagramPacket packet3 = new DatagramPacket(buf, buf.length,
+                                        new InetSocketAddress(group3, port));
+            
+            for (;;) {
+                mcastsock.send(packet1);
+                mcastsock.send(packet2);
+                mcastsock.send(packet3);
+                
+                Thread.currentThread().sleep(1000);   // sleep 1 second
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

Reply via email to