8211842: IPv6_supported wrongly returns false when unix domain socket is bound to fd 0
Reviewed-by: chegar, alanb
This commit is contained in:
parent
10d83827bc
commit
4a77a08ca3
@ -60,7 +60,7 @@ else
|
||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
|
||||
else ifeq ($(OPENJDK_TARGET_OS), solaris)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -305,12 +305,12 @@ jint IPv6_supported()
|
||||
}
|
||||
|
||||
/*
|
||||
* If fd 0 is a socket it means we've been launched from inetd or
|
||||
* If fd 0 is a socket it means we may have been launched from inetd or
|
||||
* xinetd. If it's a socket then check the family - if it's an
|
||||
* IPv4 socket then we need to disable IPv6.
|
||||
*/
|
||||
if (getsockname(0, &sa.sa, &sa_len) == 0) {
|
||||
if (sa.sa.sa_family != AF_INET6) {
|
||||
if (sa.sa.sa_family == AF_INET) {
|
||||
close(fd);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4673940 4930794
|
||||
* @bug 4673940 4930794 8211842
|
||||
* @summary Unit tests for inetd feature
|
||||
* @requires (os.family == "linux" | os.family == "solaris")
|
||||
* @library /test/lib
|
||||
@ -33,7 +33,7 @@
|
||||
* jdk.test.lib.JDKToolLauncher
|
||||
* jdk.test.lib.Platform
|
||||
* jdk.test.lib.process.*
|
||||
* StateTest StateTestService EchoTest EchoService CloseTest Launcher Util
|
||||
* UnixSocketTest StateTest StateTestService EchoTest EchoService CloseTest Launcher Util
|
||||
* @run testng/othervm/native InheritedChannelTest
|
||||
* @key intermittent
|
||||
*/
|
||||
@ -73,6 +73,7 @@ public class InheritedChannelTest {
|
||||
@DataProvider
|
||||
public Object[][] testCases() {
|
||||
return new Object[][]{
|
||||
{ "UnixSocketTest", List.of(UnixSocketTest.class.getName())},
|
||||
{ "StateTest", List.of(StateTest.class.getName()) },
|
||||
{ "EchoTest", List.of(EchoTest.class.getName()) },
|
||||
{ "CloseTest", List.of(CloseTest.class.getName()) },
|
||||
|
@ -62,6 +62,19 @@ public class Launcher {
|
||||
launch0(cmdarray, fd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Launch 'java' with specified class using a UnixDomainSocket pair linking calling
|
||||
* process to the child VM. UnixDomainSocket is a simplified interface to PF_UNIX sockets
|
||||
* which supports byte a time reads and writes.
|
||||
*/
|
||||
public static UnixDomainSocket launchWithUnixDomainSocket(String className) throws IOException {
|
||||
UnixDomainSocket[] socks = UnixDomainSocket.socketpair();
|
||||
launch(className, null, null, socks[0].fd());
|
||||
socks[0].close();
|
||||
return socks[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Launch 'java' with specified class with the specified arguments (may be null).
|
||||
* The launched process will inherit a connected TCP socket. The remote endpoint
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simplified Unix domain socket which can read and write bytes at a time
|
||||
* used for simulating external launchers which use UNIX sockets to talk
|
||||
* the VM.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnixDomainSocket {
|
||||
|
||||
static {
|
||||
System.loadLibrary("InheritedChannel");
|
||||
init();
|
||||
}
|
||||
|
||||
private final int fd;
|
||||
|
||||
public UnixDomainSocket(int fd) {
|
||||
this.fd = fd;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
return read0(fd);
|
||||
}
|
||||
|
||||
public void write(int w) throws IOException {
|
||||
write0(fd, w);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
close0(fd);
|
||||
}
|
||||
|
||||
public int fd() {
|
||||
return fd;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "UnixDomainSocket: fd=" + Integer.toString(fd);
|
||||
}
|
||||
|
||||
/* read and write bytes with UNIX domain sockets */
|
||||
|
||||
private static native int read0(int fd) throws IOException;
|
||||
private static native void write0(int fd, int w) throws IOException;
|
||||
private static native void close0(int fd);
|
||||
private static native void init();
|
||||
public static native UnixDomainSocket[] socketpair();
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If the platform has IPv6 we spawn a child process simulating the
|
||||
* effect of being launched from node.js. We check that IPv6 is available in the child
|
||||
* and report back as appropriate.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class UnixSocketTest {
|
||||
|
||||
static boolean hasIPv6() throws Exception {
|
||||
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
|
||||
for (NetworkInterface netint : Collections.list(nets)) {
|
||||
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
|
||||
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
|
||||
if (inetAddress instanceof Inet6Address) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Child {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.write('X');
|
||||
System.out.flush();
|
||||
if (hasIPv6()) {
|
||||
System.out.println("Y"); // GOOD
|
||||
} else
|
||||
System.out.println("N"); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
if (!hasIPv6()) {
|
||||
return; // can only test if IPv6 is present
|
||||
}
|
||||
UnixDomainSocket sock = Launcher.launchWithUnixDomainSocket("UnixSocketTest$Child");
|
||||
if (sock.read() != 'X') {
|
||||
System.exit(-2);
|
||||
}
|
||||
if (sock.read() != 'Y') {
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,11 @@
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#define CHECK(X) if ((X) == 0) {printf("JNI init error line %d\n", __LINE__); _exit(1);}
|
||||
|
||||
static jclass unixSocketClass;
|
||||
static jmethodID unixSocketCtor;
|
||||
|
||||
/*
|
||||
* Throws the exception of the given class name and detail message
|
||||
*/
|
||||
@ -182,3 +187,63 @@ JNIEXPORT void JNICALL Java_Launcher_launch0
|
||||
execvp(cmdv[0], cmdv);
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_init(JNIEnv *env, jclass cls) {
|
||||
CHECK(unixSocketClass = (*env)->FindClass(env, "UnixDomainSocket"));
|
||||
CHECK(unixSocketClass = (*env)->NewGlobalRef(env, unixSocketClass));
|
||||
CHECK(unixSocketCtor = (*env)->GetMethodID(env, unixSocketClass, "<init>", "(I)V"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: UnixDomainSocket
|
||||
* Method: socketpair
|
||||
* Signature: ()[LUnixDomainSocket
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_UnixDomainSocket_socketpair
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
int fds[2];
|
||||
jobject socket;
|
||||
jobjectArray result = (*env)->NewObjectArray(env, 2, unixSocketClass, 0);
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
|
||||
perror("socketpair");
|
||||
return result;
|
||||
}
|
||||
socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[0]);
|
||||
(*env)->SetObjectArrayElement(env, result, 0, socket);
|
||||
socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[1]);
|
||||
(*env)->SetObjectArrayElement(env, result, 1, socket);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_UnixDomainSocket_read0
|
||||
(JNIEnv *env, jclass cls, jint fd)
|
||||
{
|
||||
int ret;
|
||||
unsigned char res;
|
||||
ret = read(fd, &res, 1);
|
||||
if (ret == 0)
|
||||
return -1; /* EOF */
|
||||
else if (ret < 0) {
|
||||
ThrowException(env, "java/io/IOException", "read error");
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_write0
|
||||
(JNIEnv *env, jclass cls, jint fd, jint byte)
|
||||
{
|
||||
int ret;
|
||||
unsigned char w = (unsigned char)byte;
|
||||
ret = write(fd, &w, 1);
|
||||
if (ret < 0) {
|
||||
ThrowException(env, "java/io/IOException", "write error");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_close0
|
||||
(JNIEnv *env, jclass cls, jint fd)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user