8233307: MulticastSocket getOption(IP_MULTICAST_IF) returns interface when not set

The MulticastSocket method getOption has been changed to conform to the behavior described in StandardSocketOptions.IP_MULTICAST_IF.

Reviewed-by: chegar, dfuchs
This commit is contained in:
Patrick Concannon 2019-11-28 16:49:52 +00:00
parent 558aadf608
commit 55da7d34c9
4 changed files with 150 additions and 67 deletions

View File

@ -576,7 +576,7 @@ public class MulticastSocket extends DatagramSocket {
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);

View File

@ -1494,25 +1494,7 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
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 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) {
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;
}

View File

@ -1691,7 +1691,6 @@ static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint
static jfieldID ni_indexID;
static jfieldID ni_addrsID;
jobjectArray addrArray;
jobject addr;
jobject ni;
@ -1749,19 +1748,7 @@ static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint
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 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o
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;
}

View File

@ -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<InetAddress> 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");
}
}
}
}