# HG changeset patch # User pconcannon # Date 1574959792 0 # Node ID 6f12009ea9d753e471d900f470b6e937d4a65a4e # Parent 43eee12379347bba49c34b5945a396473f773188 8233307: MulticastSocket getOption(IP_MULTICAST_IF) returns interface when not set Summary: The MulticastSocket method getOption has been changed to conform to the behavior described in StandardSocketOptions.IP_MULTICAST_IF. Reviewed-by: chegar, dfuchs diff -r 43eee1237934 -r 6f12009ea9d7 src/java.base/share/classes/java/net/MulticastSocket.java --- a/src/java.base/share/classes/java/net/MulticastSocket.java Thu Nov 28 18:30:18 2019 +0100 +++ b/src/java.base/share/classes/java/net/MulticastSocket.java Thu Nov 28 16:49:52 2019 +0000 @@ -576,7 +576,7 @@ public NetworkInterface getNetworkInterface() throws SocketException { NetworkInterface ni = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); - if ((ni.getIndex() == 0) || (ni.getIndex() == -1)) { + if (ni == null) { InetAddress[] addrs = new InetAddress[1]; addrs[0] = InetAddress.anyLocalAddress(); return new NetworkInterface(addrs[0].getHostName(), 0, addrs); diff -r 43eee1237934 -r 6f12009ea9d7 src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Thu Nov 28 18:30:18 2019 +0100 +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Thu Nov 28 16:49:52 2019 +0000 @@ -1494,25 +1494,7 @@ if (ni) { return ni; } - - /* - * The address doesn't appear to be bound at any known - * NetworkInterface. Therefore we construct a NetworkInterface - * with this address. - */ - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - ni_name = (*env)->NewStringUTF(env, ""); - if (ni_name != NULL) { - (*env)->SetObjectField(env, ni, ni_nameID, ni_name); - } - return ni; + return NULL; } @@ -1619,19 +1601,6 @@ if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { return addr; } - - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - ni_name = (*env)->NewStringUTF(env, ""); - if (ni_name != NULL) { - (*env)->SetObjectField(env, ni, ni_nameID, ni_name); - } - return ni; } return NULL; } diff -r 43eee1237934 -r 6f12009ea9d7 src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c --- a/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Thu Nov 28 18:30:18 2019 +0100 +++ b/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Thu Nov 28 16:49:52 2019 +0000 @@ -1691,7 +1691,6 @@ static jfieldID ni_indexID; static jfieldID ni_addrsID; - jobjectArray addrArray; jobject addr; jobject ni; @@ -1749,19 +1748,7 @@ if (ni) { return ni; } - if (ipv4Mode) { - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - } else { - ni = NULL; - } - return ni; + return NULL; } /* @@ -1898,26 +1885,6 @@ return netObject; } } - - /* - * Multicast to any address - return anyLocalAddress - * or a NetworkInterface with addrs[0] set to anyLocalAddress - */ - - addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID, - NULL); - if (opt == java_net_SocketOptions_IP_MULTICAST_IF) { - return addr; - } - - ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0); - CHECK_NULL_RETURN(ni, NULL); - (*env)->SetIntField(env, ni, ni_indexID, -1); - addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL); - CHECK_NULL_RETURN(addrArray, NULL); - (*env)->SetObjectArrayElement(env, addrArray, 0, addr); - (*env)->SetObjectField(env, ni, ni_addrsID, addrArray); - return ni; } return NULL; } diff -r 43eee1237934 -r 6f12009ea9d7 test/jdk/java/net/NetworkInterface/NoSetNetworkInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/net/NetworkInterface/NoSetNetworkInterface.java Thu Nov 28 16:49:52 2019 +0000 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019, 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 8233307 + * @library /test/lib + * @run main/othervm NoSetNetworkInterface + * @run main/othervm -Djava.net.preferIPv4Stack=true NoSetNetworkInterface + * @run main/othervm -Djava.net.preferIPv6Addresses=true NoSetNetworkInterface + * @summary Check that methods that are used to set and get the NetworkInterface + * for a MulticastSocket work as expected. This test also checks that getOption + * returns null correctly when a NetworkInterface has not been set + */ + +import jdk.test.lib.NetworkConfiguration; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.MulticastSocket; +import java.net.NetworkInterface; +import java.net.StandardSocketOptions; +import java.util.Optional; +import java.util.function.Predicate; + +public class NoSetNetworkInterface { + public static void main(String[] args) throws Exception { + + NetworkConfiguration nc = NetworkConfiguration.probe(); + + // check set and get methods work as expected + nc.multicastInterfaces(true).forEach(ni -> { + checkSetInterface(ni); + checkSetNetworkInterface(ni); + checkSetOption(ni); + }); + + // Check that dummy NetworkInterface is returned when not set + checkDummyNetworkInterface(); + } + + public static void checkSetInterface(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + Optional iAddr = ni.inetAddresses() + .filter(Predicate.not(InetAddress::isAnyLocalAddress)) + .findFirst(); + if (iAddr.isPresent()) { + ms.setInterface(iAddr.get()); + checkForCorrectNetworkInterface("setInterface", ms, ni); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkSetNetworkInterface(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + ms.setNetworkInterface(ni); + checkForCorrectNetworkInterface("setNetworkInterface", ms, ni); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkSetOption(NetworkInterface ni) { + try (MulticastSocket ms = new MulticastSocket()) { + ms.setOption(StandardSocketOptions.IP_MULTICAST_IF, ni); + checkForCorrectNetworkInterface("setOption", ms, ni); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void checkForCorrectNetworkInterface(String setterMethod, + MulticastSocket ms, + NetworkInterface ni) throws IOException { + + // getInterface + InetAddress testAddr = ms.getInterface(); + if (!ni.inetAddresses().anyMatch(i -> i.equals(testAddr))) { + throw new RuntimeException(setterMethod + " != getInterface"); + } + + // getNetworkInterface + if (!ni.equals(ms.getNetworkInterface())) { + throw new RuntimeException(setterMethod + " != getNetworkInterface"); + } + + // getOption + if (!ni.equals(ms.getOption(StandardSocketOptions.IP_MULTICAST_IF))) { + throw new RuntimeException(setterMethod + " != getOption"); + } + } + + public static void checkDummyNetworkInterface() throws IOException { + + try(MulticastSocket ms = new MulticastSocket()) { + + // getOption with no Network Interface set + NetworkInterface n0 = ms.getOption(StandardSocketOptions.IP_MULTICAST_IF); + if (n0 != null) { + throw new RuntimeException("NetworkInterface should be null"); + } + + // getNetworkInterface with no Network Interface set + NetworkInterface n1 = ms.getNetworkInterface(); + if (n1 == null) { + throw new RuntimeException("getNetworkInterface() should not return null"); + } else if (!((n1.getName().equals("0.0.0.0") || n1.getName().equals("::")) + && (n1.getIndex() == 0) + && (n1.inetAddresses().count() == 1))) { + + throw new RuntimeException("Dummy NetworkInterface not returned as expected"); + } + + // getInterface with no Network Interface set + InetAddress iaddr = ms.getInterface(); + if (iaddr == null) { + throw new RuntimeException("getInterface() should not return null"); + } else if (!iaddr.isAnyLocalAddress()) { + throw new RuntimeException("getInterface() should return anyLocalAddress"); + } + } + } +} +