# HG changeset patch # User chegar # Date 1461780767 -3600 # Wed Apr 27 19:12:47 2016 +0100 # Node ID 94ae5432b6a99ad7798932e5cc503c6dbe834d37 # Parent ee0a64ae78db171d3174b36a392959989dd9861e 8044773: Refactor jdk.net API so that it can be moved out of the base module Reviewed-by: diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk new file mode 100644 --- /dev/null +++ b/make/lib/Lib-jdk.net.gmk @@ -0,0 +1,51 @@ +# +# Copyright (c) 2016, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +include LibCommon.gmk + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), solaris) + + $(eval $(call SetupNativeCompilation, BUILD_LIBEXTNET, \ + LIBRARY := extnet, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(JDK_TOPDIR)/src/jdk.net/solaris/native/libextnet, \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.net, \ + MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libextnet/mapfile-vers, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ + LIBS := -lsocket -lc -ljava, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libextnet, \ + )) + + $(BUILD_LIBEXTNET): $(call FindLib, java.base, java) + + TARGETS += $(BUILD_LIBEXTNET) +endif + + +################################################################################ diff --git a/make/mapfiles/libextnet/mapfile-vers b/make/mapfiles/libextnet/mapfile-vers new file mode 100644 --- /dev/null +++ b/make/mapfiles/libextnet/mapfile-vers @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +SUNWprivate_1.1 { + global: + Java_jdk_net_SolarisSocketOptions_init; + Java_jdk_net_SolarisSocketOptions_setFlowOption; + Java_jdk_net_SolarisSocketOptions_getFlowOption; + Java_jdk_net_SolarisSocketOptions_flowSupported; + local: + *; +}; diff --git a/make/mapfiles/libnet/mapfile-vers b/make/mapfiles/libnet/mapfile-vers --- a/make/mapfiles/libnet/mapfile-vers +++ b/make/mapfiles/libnet/mapfile-vers @@ -98,10 +98,6 @@ Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; - Java_sun_net_ExtendedOptionsImpl_init; - Java_sun_net_ExtendedOptionsImpl_setFlowOption; - Java_sun_net_ExtendedOptionsImpl_getFlowOption; - Java_sun_net_ExtendedOptionsImpl_flowSupported; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/make/src/classes/build/tools/module/GenModuleInfoSource.java b/make/src/classes/build/tools/module/GenModuleInfoSource.java --- a/make/src/classes/build/tools/module/GenModuleInfoSource.java +++ b/make/src/classes/build/tools/module/GenModuleInfoSource.java @@ -52,7 +52,7 @@ "Usage: GenModuleInfoSource [option] -o \n" + "Options are:\n" + " -exports \n" + - " -exports /\n" + + " -exports [/]\n" + " -uses \n" + " -provides /\n"; diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -83,8 +83,6 @@ // see JDK-8144062 exports jdk; - // see JDK-8044773 - exports jdk.net; // the service types defined by the APIs in this module @@ -194,6 +192,8 @@ jdk.jvmstat; exports sun.net to java.httpclient; + exports sun.net.ext to + jdk.net; exports sun.net.dns to java.security.jgss, jdk.naming.dns; diff --git a/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java b/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java deleted file mode 100644 --- a/src/java.base/share/classes/sun/net/ExtendedOptionsImpl.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package sun.net; - -import java.net.*; -import jdk.net.*; -import java.io.IOException; -import java.io.FileDescriptor; -import java.security.PrivilegedAction; -import java.security.AccessController; -import java.lang.reflect.Field; -import java.util.Set; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Collections; - -/** - * Contains the native implementation for extended socket options - * together with some other static utilities - */ -public class ExtendedOptionsImpl { - - static { - AccessController.doPrivileged((PrivilegedAction)() -> { - System.loadLibrary("net"); - return null; - }); - init(); - } - - private ExtendedOptionsImpl() {} - - public static void checkSetOptionPermission(SocketOption option) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return; - } - String check = "setOption." + option.name(); - sm.checkPermission(new NetworkPermission(check)); - } - - public static void checkGetOptionPermission(SocketOption option) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return; - } - String check = "getOption." + option.name(); - sm.checkPermission(new NetworkPermission(check)); - } - - public static void checkValueType(Object value, Class type) { - if (!type.isAssignableFrom(value.getClass())) { - String s = "Found: " + value.getClass().toString() + " Expected: " - + type.toString(); - throw new IllegalArgumentException(s); - } - } - - private static native void init(); - - /* - * Extension native implementations - * - * SO_FLOW_SLA - */ - public static native void setFlowOption(FileDescriptor fd, SocketFlow f); - public static native void getFlowOption(FileDescriptor fd, SocketFlow f); - public static native boolean flowSupported(); -} diff --git a/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java new file mode 100644 --- /dev/null +++ b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.net.ext; + +import java.io.FileDescriptor; +import java.net.SocketException; +import java.net.SocketOption; +import java.util.Collections; +import java.util.Set; + +/** + * Defines the infrastructure to support extended socket options, beyond those + * defined in {@link java.net.StandardSocketOptions}. + * + * Extended socket options are accessed through the jdk.net API, which is in + * the jdk.net module. + */ +public abstract class ExtendedSocketOptions { + + private final Set> options; + + /** Tells whether or not the option is supported. */ + public final boolean isOptionSupported(SocketOption option) { + return options().contains(option); + } + + /** Return the, possibly empty, set of extended socket options available. */ + public final Set> options() { return options; } + + /** Sets the value of a socket option, for the given socket. */ + public abstract void setOption(FileDescriptor fd, SocketOption option, Object value) + throws SocketException; + + /** Returns the value of a socket option, for the given socket. */ + public abstract Object getOption(FileDescriptor fd, SocketOption option) + throws SocketException; + + protected ExtendedSocketOptions(Set> options) { + this.options = options; + } + + private static volatile ExtendedSocketOptions instance; + + public static final ExtendedSocketOptions getInstance() { return instance; } + + /** Registers support for extended socket options. Invoked by the jdk.net module. */ + public static final void register(ExtendedSocketOptions extOptions) { + if (instance != null) + throw new InternalError("Attempting to reregister extended options"); + + instance = extOptions; + } + + static { + try { + // If the class is present, it will be initialized which + // triggers registration of the extended socket options. + Class c = Class.forName("jdk.net.ExtendedSocketOptions"); + } catch (ClassNotFoundException e) { + // the jdk.net module is not present => no extended socket options + instance = new NoExtendedSocketOptions(); + } + } + + static final class NoExtendedSocketOptions extends ExtendedSocketOptions { + + NoExtendedSocketOptions() { + super(Collections.unmodifiableSet(Collections.>emptySet())); + } + + @Override + public void setOption(FileDescriptor fd, SocketOption option, Object value) + throws SocketException + { + throw new UnsupportedOperationException("no extended options"); + } + + @Override + public Object getOption(FileDescriptor fd, SocketOption option) + throws SocketException + { + throw new UnsupportedOperationException("no extended options"); + } + } +} diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -39,7 +39,7 @@ import java.util.concurrent.*; import java.util.concurrent.locks.*; import sun.net.NetHooks; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; /** * Base implementation of AsynchronousSocketChannel @@ -512,9 +512,9 @@ set.add(StandardSocketOptions.SO_REUSEPORT); } set.add(StandardSocketOptions.TCP_NODELAY); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -33,7 +33,7 @@ import java.nio.channels.spi.*; import java.util.*; import sun.net.ResourceManager; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; /** * An implementation of DatagramChannels. @@ -306,9 +306,9 @@ set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); set.add(StandardSocketOptions.IP_MULTICAST_LOOP); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java --- a/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/src/java.base/share/classes/sun/nio/ch/Net.java @@ -27,15 +27,13 @@ import java.io.*; import java.net.*; -import jdk.net.*; import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.net.ExtendedOptionsImpl; +import sun.net.ext.ExtendedSocketOptions; import sun.security.action.GetPropertyAction; - public class Net { private Net() { } @@ -281,6 +279,9 @@ // -- Socket options + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + static void setSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption name, Object value) throws IOException @@ -291,12 +292,8 @@ // only simple values supported by this method Class type = name.type(); - if (type == SocketFlow.class) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA")); - } - ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value); + if (extendedOptions.isOptionSupported(name)) { + extendedOptions.setOption(fd, name, value); return; } @@ -353,14 +350,8 @@ { Class type = name.type(); - if (type == SocketFlow.class) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA")); - } - SocketFlow flow = SocketFlow.create(); - ExtendedOptionsImpl.getFlowOption(fd, flow); - return flow; + if (extendedOptions.isOptionSupported(name)) { + return extendedOptions.getOption(fd, name); } // only simple values supported by this method diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -33,8 +33,7 @@ import java.nio.channels.spi.*; import java.util.*; import sun.net.NetHooks; -import sun.net.ExtendedOptionsImpl; - +import sun.net.ext.ExtendedSocketOptions; /** * An implementation of SocketChannels @@ -242,9 +241,9 @@ // additional options required by socket adaptor set.add(StandardSocketOptions.IP_TOS); set.add(ExtendedSocketOption.SO_OOBINLINE); - if (ExtendedOptionsImpl.flowSupported()) { - set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); - } + ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + set.addAll(extendedOptions.options()); return Collections.unmodifiableSet(set); } } diff --git a/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java b/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java --- a/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java +++ b/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java @@ -27,9 +27,7 @@ import java.io.IOException; import java.util.Set; import java.util.HashSet; -import java.util.Collections; -import jdk.net.*; -import static sun.net.ExtendedOptionsImpl.*; +import sun.net.ext.ExtendedSocketOptions; /* * On Unix systems we simply delegate to native methods. @@ -43,8 +41,11 @@ init(); } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + protected void setOption(SocketOption name, T value) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { super.setOption(name, value); } else { @@ -55,21 +56,16 @@ } } } else { - if (!flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } if (isClosed()) { throw new SocketException("Socket closed"); } - checkSetOptionPermission(name); - checkValueType(value, SocketFlow.class); - setFlowOption(getFileDescriptor(), (SocketFlow)value); + extendedOptions.setOption(fd, name, value); } } @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { return super.getOption(name); } else { @@ -79,31 +75,23 @@ throw new UnsupportedOperationException("unsupported option"); } } + } else { + if (isClosed()) { + throw new SocketException("Socket closed"); + } + return (T) extendedOptions.getOption(fd, name); } - if (!flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } - if (isClosed()) { - throw new SocketException("Socket closed"); - } - checkGetOptionPermission(name); - SocketFlow flow = SocketFlow.create(); - getFlowOption(getFileDescriptor(), flow); - return (T)flow; } protected Set> supportedOptions() { - HashSet> options = new HashSet<>( - super.supportedOptions()); - - if (flowSupported()) { - options.add(ExtendedSocketOptions.SO_FLOW_SLA); - } + HashSet> options = new HashSet<>(super.supportedOptions()); + options.addAll(extendedOptions.options()); return options; } protected void socketSetOption(int opt, Object val) throws SocketException { - if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + if (opt == SocketOptions.SO_REUSEPORT && + !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { throw new UnsupportedOperationException("unsupported option"); } try { diff --git a/src/java.base/unix/classes/java/net/PlainSocketImpl.java b/src/java.base/unix/classes/java/net/PlainSocketImpl.java --- a/src/java.base/unix/classes/java/net/PlainSocketImpl.java +++ b/src/java.base/unix/classes/java/net/PlainSocketImpl.java @@ -28,10 +28,7 @@ import java.io.FileDescriptor; import java.util.Set; import java.util.HashSet; -import java.util.Collections; -import jdk.net.*; - -import static sun.net.ExtendedOptionsImpl.*; +import sun.net.ext.ExtendedSocketOptions; /* * On Unix systems we simply delegate to native methods. @@ -57,8 +54,11 @@ this.fd = fd; } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + protected void setOption(SocketOption name, T value) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { super.setOption(name, value); } else { @@ -69,21 +69,19 @@ } } } else { - if (getSocket() == null || !flowSupported()) { + if (getSocket() == null) { throw new UnsupportedOperationException("unsupported option"); } if (isClosedOrPending()) { throw new SocketException("Socket closed"); } - checkSetOptionPermission(name); - checkValueType(value, SocketFlow.class); - setFlowOption(getFileDescriptor(), (SocketFlow)value); + extendedOptions.setOption(fd, name, value); } } @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { - if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + if (!extendedOptions.isOptionSupported(name)) { if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { return super.getOption(name); } else { @@ -93,31 +91,28 @@ throw new UnsupportedOperationException("unsupported option"); } } + } else { + if (getSocket() == null) { + throw new UnsupportedOperationException("unsupported option"); + } + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + return (T) extendedOptions.getOption(fd, name); } - if (getSocket() == null || !flowSupported()) { - throw new UnsupportedOperationException("unsupported option"); - } - if (isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - checkGetOptionPermission(name); - SocketFlow flow = SocketFlow.create(); - getFlowOption(getFileDescriptor(), flow); - return (T)flow; } protected Set> supportedOptions() { - HashSet> options = new HashSet<>( - super.supportedOptions()); - - if (getSocket() != null && flowSupported()) { - options.add(ExtendedSocketOptions.SO_FLOW_SLA); + HashSet> options = new HashSet<>(super.supportedOptions()); + if (getSocket() != null) { + options.addAll(extendedOptions.options()); } return options; } protected void socketSetOption(int opt, boolean b, Object val) throws SocketException { - if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + if (opt == SocketOptions.SO_REUSEPORT && + !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { throw new UnsupportedOperationException("unsupported option"); } try { diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -120,47 +120,6 @@ #ifdef __solaris__ int net_getParam(char *driver, char *param); - -#ifndef SO_FLOW_SLA -#define SO_FLOW_SLA 0x1018 - -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack(4) #endif -/* - * Used with the setsockopt(SO_FLOW_SLA, ...) call to set - * per socket service level properties. - * When the application uses per-socket API, we will enforce the properties - * on both outbound and inbound packets. - * - * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. - */ -typedef struct sock_flow_props_s { - int sfp_version; - uint32_t sfp_mask; - int sfp_priority; /* flow priority */ - uint64_t sfp_maxbw; /* bandwidth limit in bps */ - int sfp_status; /* flow create status for getsockopt */ -} sock_flow_props_t; - -#define SOCK_FLOW_PROP_VERSION1 1 - -/* bit mask values for sfp_mask */ -#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ -#define SFP_PRIORITY 0x00000008 /* Flow priority */ - -/* possible values for sfp_priority */ -#define SFP_PRIO_NORMAL 1 -#define SFP_PRIO_HIGH 2 - -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack() -#endif /* _LONG_LONG_ALIGNMENT */ - -#endif /* SO_FLOW_SLA */ -#endif /* __solaris__ */ - -JNIEXPORT jboolean JNICALL NET_IsFlowSupported(); - #endif /* NET_UTILS_MD_H */ diff --git a/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c b/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c deleted file mode 100644 --- a/src/java.base/windows/native/libnet/ExtendedOptionsImpl.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -#include -#include - -#include "net_util.h" - -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: init - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init - (JNIEnv *env, jclass UNUSED) -{ -} - -/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -static jboolean flowSupported0() { - return JNI_FALSE; -} - -JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported - (JNIEnv *env, jclass UNUSED) -{ - return JNI_FALSE; -} diff --git a/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java rename from src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java rename to src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java --- a/src/java.base/share/classes/jdk/net/ExtendedSocketOptions.java +++ b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java @@ -25,7 +25,15 @@ package jdk.net; +import java.io.FileDescriptor; +import java.net.SocketException; import java.net.SocketOption; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.Set; +import jdk.internal.misc.JavaIOFileDescriptorAccess; +import jdk.internal.misc.SharedSecrets; /** * Defines extended socket options, beyond those defined in @@ -48,7 +56,7 @@ @Override public String toString() { return name; } } - private ExtendedSocketOptions() {} + private ExtendedSocketOptions() { } /** * Service level properties. When a security manager is installed, @@ -58,4 +66,147 @@ */ public static final SocketOption SO_FLOW_SLA = new ExtSocketOption("SO_FLOW_SLA", SocketFlow.class); + + + private static final PlatformSocketOptions platformSocketOptions = + PlatformSocketOptions.get(); + + private static final boolean flowSupported = + platformSocketOptions.flowSupported(); + + private static final Set> extendedOptions = options(); + + static Set> options() { + if (flowSupported) + return Set.of(SO_FLOW_SLA); + else + return Collections.unmodifiableSet(Collections.>emptySet()); + } + + static { + // Registers the extended socket options with the base module. + sun.net.ext.ExtendedSocketOptions.register( + new sun.net.ext.ExtendedSocketOptions(extendedOptions) { + + @Override + public void setOption(FileDescriptor fd, + SocketOption option, + Object value) + throws SocketException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetworkPermission("setOption." + option.name())); + + if (fd == null || !fd.valid()) + throw new SocketException("socket closed"); + + if (option == SO_FLOW_SLA) { + assert flowSupported; + SocketFlow flow = checkValueType(value, option.type()); + setFlowOption(fd, flow); + } else { + throw new InternalError("Unexpected option " + option); + } + } + + @Override + public Object getOption(FileDescriptor fd, + SocketOption option) + throws SocketException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new NetworkPermission("getOption." + option.name())); + + if (fd == null || !fd.valid()) + throw new SocketException("socket closed"); + + if (option == SO_FLOW_SLA) { + assert flowSupported; + SocketFlow flow = SocketFlow.create(); + getFlowOption(fd, flow); + return flow; + } else { + throw new InternalError("Unexpected option " + option); + } + } + }); + } + + @SuppressWarnings("unchecked") + private static T checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass() + ", Expected: " + type; + throw new IllegalArgumentException(s); + } + return (T) value; + } + + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private static void setFlowOption(FileDescriptor fd, SocketFlow f) + throws SocketException + { + int status = platformSocketOptions.setFlowOption(fdAccess.get(fd), + f.priority(), + f.bandwidth()); + f.status(status); // augment the given flow with the status + } + + private static void getFlowOption(FileDescriptor fd, SocketFlow f) + throws SocketException + { + int status = platformSocketOptions.getFlowOption(fdAccess.get(fd), f); + f.status(status); // augment the given flow with the status + } + + static class PlatformSocketOptions { + + protected PlatformSocketOptions() {} + + @SuppressWarnings("unchecked") + private static PlatformSocketOptions newInstance(String cn) { + Class c; + try { + c = (Class)Class.forName(cn); + return c.getConstructor(new Class[] { }).newInstance(); + } catch (ReflectiveOperationException x) { + throw new AssertionError(x); + } + } + + private static PlatformSocketOptions create() { + String osname = AccessController.doPrivileged( + new PrivilegedAction() { + public String run() { + return System.getProperty("os.name"); + } + }); + if ("SunOS".equals(osname)) + return newInstance("jdk.net.SolarisSocketOptions"); + return new PlatformSocketOptions(); + } + + private static final PlatformSocketOptions instance = create(); + + static PlatformSocketOptions get() { + return instance; + } + + int setFlowOption(int fd, int priority, long bandwidth) + throws SocketException + { + throw new UnsupportedOperationException("unsupported socket option"); + } + + int getFlowOption(int fd, SocketFlow f) throws SocketException { + throw new UnsupportedOperationException("unsupported socket option"); + } + + boolean flowSupported() { + return false; + } + } } diff --git a/src/java.base/share/classes/jdk/net/NetworkPermission.java b/src/jdk.net/share/classes/jdk/net/NetworkPermission.java rename from src/java.base/share/classes/jdk/net/NetworkPermission.java rename to src/jdk.net/share/classes/jdk/net/NetworkPermission.java diff --git a/src/java.base/share/classes/jdk/net/SocketFlow.java b/src/jdk.net/share/classes/jdk/net/SocketFlow.java rename from src/java.base/share/classes/jdk/net/SocketFlow.java rename to src/jdk.net/share/classes/jdk/net/SocketFlow.java --- a/src/java.base/share/classes/jdk/net/SocketFlow.java +++ b/src/jdk.net/share/classes/jdk/net/SocketFlow.java @@ -47,17 +47,18 @@ */ public class SocketFlow { - private static final int UNSET = -1; + @Native public static final int UNSET = -1; @Native public static final int NORMAL_PRIORITY = 1; @Native public static final int HIGH_PRIORITY = 2; - private int priority = NORMAL_PRIORITY; - - private long bandwidth = UNSET; - - private Status status = Status.NO_STATUS; - - private SocketFlow() {} + @Native private static final int NO_STATUS_VALUE = 0; + @Native private static final int OK_VALUE = 1; + @Native private static final int NO_PERMISSION_VALUE = 2; + @Native private static final int NOT_CONNECTED_VALUE = 3; + @Native private static final int NOT_SUPPORTED_VALUE = 4; + @Native private static final int ALREADY_CREATED_VALUE = 5; + @Native private static final int IN_PROGRESS_VALUE = 6; + @Native private static final int OTHER_VALUE = 7; /** * Enumeration of the return values from the SO_FLOW_SLA @@ -72,37 +73,56 @@ * Set or get socket option has not been called yet. Status * values can only be retrieved after calling set or get. */ - NO_STATUS, + NO_STATUS(NO_STATUS_VALUE), /** * Flow successfully created. */ - OK, + OK(OK_VALUE), /** * Caller has no permission to create flow. */ - NO_PERMISSION, + NO_PERMISSION(NO_PERMISSION_VALUE), /** * Flow can not be created because socket is not connected. */ - NOT_CONNECTED, + NOT_CONNECTED(NOT_CONNECTED_VALUE), /** * Flow creation not supported for this socket. */ - NOT_SUPPORTED, + NOT_SUPPORTED(NOT_SUPPORTED_VALUE), /** * A flow already exists with identical attributes. */ - ALREADY_CREATED, + ALREADY_CREATED(ALREADY_CREATED_VALUE), /** * A flow is being created. */ - IN_PROGRESS, + IN_PROGRESS(IN_PROGRESS_VALUE), /** * Some other unspecified error. */ - OTHER + OTHER(OTHER_VALUE); + + private final int value; + Status(int value) { this.value = value; } + + static Status from(int value) { + if (value == NO_STATUS.value) return NO_STATUS; + else if (value == OK.value) return OK; + else if (value == NO_PERMISSION.value) return NO_PERMISSION; + else if (value == NOT_CONNECTED.value) return NOT_CONNECTED; + else if (value == NOT_SUPPORTED.value) return NOT_SUPPORTED; + else if (value == ALREADY_CREATED.value) return ALREADY_CREATED; + else if (value == IN_PROGRESS.value) return IN_PROGRESS; + else if (value == OTHER.value) return OTHER; + else throw new InternalError("Unknown value: " + value); + } } + private int priority = NORMAL_PRIORITY; + private long bandwidth = UNSET; + private Status status = Status.NO_STATUS; + /** * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA * socket option and create a socket flow. @@ -111,6 +131,8 @@ return new SocketFlow(); } + private SocketFlow() { } + /** * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY * HIGH_PRIORITY. If not set, a flow's priority is normal. @@ -119,9 +141,8 @@ * HIGH_PRIORITY. */ public SocketFlow priority(int priority) { - if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) { - throw new IllegalArgumentException("invalid priority"); - } + if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) + throw new IllegalArgumentException("invalid priority :" + priority); this.priority = priority; return this; } @@ -133,11 +154,9 @@ * @throws IllegalArgumentException if bandwidth is less than zero. */ public SocketFlow bandwidth(long bandwidth) { - if (bandwidth < 0) { - throw new IllegalArgumentException("invalid bandwidth"); - } else { - this.bandwidth = bandwidth; - } + if (bandwidth < 0) + throw new IllegalArgumentException("invalid bandwidth: " + bandwidth); + this.bandwidth = bandwidth; return this; } @@ -164,4 +183,18 @@ public Status status() { return status; } + + void status(int status) { + this.status = Status.from(status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()); + sb.append(" [ priority=").append(priority()) + .append(", bandwidth=").append(bandwidth()) + .append(", status=").append(status()) + .append(" ]"); + return sb.toString(); + } } diff --git a/src/java.base/share/classes/jdk/net/Sockets.java b/src/jdk.net/share/classes/jdk/net/Sockets.java rename from src/java.base/share/classes/jdk/net/Sockets.java rename to src/jdk.net/share/classes/jdk/net/Sockets.java --- a/src/java.base/share/classes/jdk/net/Sockets.java +++ b/src/jdk.net/share/classes/jdk/net/Sockets.java @@ -27,15 +27,12 @@ import java.net.*; import java.io.IOException; -import java.io.FileDescriptor; -import java.security.PrivilegedAction; -import java.security.AccessController; -import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; import java.util.Set; -import java.util.HashSet; -import java.util.HashMap; -import java.util.Collections; -import sun.net.ExtendedOptionsImpl; +import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; /** * Defines static methods to set and get socket options defined by the @@ -57,12 +54,8 @@ */ public class Sockets { - private static final HashMap,Set>> - options = new HashMap<>(); - - static { - initOptionSets(); - } + private static final Map,Set>> + options = optionSets(); private Sockets() {} @@ -259,14 +252,16 @@ */ static boolean isReusePortAvailable() { if (!checkedReusePort) { - isReusePortAvailable = isReusePortAvailable0(); + Set> s = new Socket().supportedOptions(); + isReusePortAvailable = s.contains(StandardSocketOptions.SO_REUSEPORT); checkedReusePort = true; } return isReusePortAvailable; } - private static void initOptionSets() { - boolean flowsupported = ExtendedOptionsImpl.flowSupported(); + private static Map,Set>> optionSets() { + Map,Set>> options = new HashMap<>(); + boolean flowsupported = PlatformSocketOptions.get().flowSupported(); boolean reuseportsupported = isReusePortAvailable(); // Socket @@ -333,7 +328,7 @@ } set = Collections.unmodifiableSet(set); options.put(MulticastSocket.class, set); + + return Collections.unmodifiableMap(options); } - - private static native boolean isReusePortAvailable0(); } diff --git a/src/java.base/share/classes/jdk/net/package-info.java b/src/jdk.net/share/classes/jdk/net/package-info.java rename from src/java.base/share/classes/jdk/net/package-info.java rename to src/jdk.net/share/classes/jdk/net/package-info.java diff --git a/src/jdk.net/share/classes/module-info.java b/src/jdk.net/share/classes/module-info.java new file mode 100644 --- /dev/null +++ b/src/jdk.net/share/classes/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +module jdk.net { + exports jdk.net; +} + diff --git a/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java b/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java new file mode 100644 --- /dev/null +++ b/src/jdk.net/solaris/classes/jdk/net/SolarisSocketOptions.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.net; + +import java.net.SocketException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; + +class SolarisSocketOptions extends PlatformSocketOptions { + + public SolarisSocketOptions() { } + + @Override native int setFlowOption(int fd, int priority, long bandwidth) + throws SocketException; + + @Override native int getFlowOption(int fd, SocketFlow f) + throws SocketException; + + @Override native boolean flowSupported(); + + private static native void init(); + + static { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + System.loadLibrary("extnet"); + return null; + } + }); + init(); + } +} diff --git a/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c rename from src/java.base/unix/native/libnet/ExtendedOptionsImpl.c rename to src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -23,278 +23,142 @@ * questions. */ -#include -#include -#include "net_util.h" -#include "jdk_net_SocketFlow.h" +#include "SolarisSocketOptions.h" -static jclass sf_status_class; /* Status enum type */ - -static jfieldID sf_status; static jfieldID sf_priority; static jfieldID sf_bandwidth; -static jfieldID sf_fd_fdID; /* FileDescriptor.fd */ - -/* References to the literal enum values */ - -static jobject sfs_NOSTATUS; -static jobject sfs_OK; -static jobject sfs_NOPERMISSION; -static jobject sfs_NOTCONNECTED; -static jobject sfs_NOTSUPPORTED; -static jobject sfs_ALREADYCREATED; -static jobject sfs_INPROGRESS; -static jobject sfs_OTHER; - -static jobject getEnumField(JNIEnv *env, char *name); -static void setStatus(JNIEnv *env, jobject obj, int errval); - -/* OS specific code is implemented in these three functions */ - -static jboolean flowSupported0() ; +static int initialized = 0; /* - * Class: sun_net_ExtendedOptionsImpl + * Class: jdk_net_SolarisSocketOptions * Method: init * Signature: ()V */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init - (JNIEnv *env, jclass UNUSED) +JNIEXPORT void JNICALL Java_jdk_net_SolarisSocketOptions_init + (JNIEnv *env, jclass unused) { - static int initialized = 0; - jclass c; - - /* Global class references */ - - if (initialized) { - return; + if (!initialized) { + jclass c = (*env)->FindClass(env, "jdk/net/SocketFlow"); + CHECK_NULL(c); + sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); + CHECK_NULL(sf_priority); + sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); + CHECK_NULL(sf_bandwidth); + initialized = 1; } - - c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status"); - CHECK_NULL(c); - sf_status_class = (*env)->NewGlobalRef(env, c); - CHECK_NULL(sf_status_class); - - /* int "fd" field of java.io.FileDescriptor */ - - c = (*env)->FindClass(env, "java/io/FileDescriptor"); - CHECK_NULL(c); - sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I"); - CHECK_NULL(sf_fd_fdID); - - - /* SocketFlow fields */ - - c = (*env)->FindClass(env, "jdk/net/SocketFlow"); - CHECK_NULL(c); - - /* status */ - - sf_status = (*env)->GetFieldID(env, c, "status", - "Ljdk/net/SocketFlow$Status;"); - CHECK_NULL(sf_status); - - /* priority */ - - sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); - CHECK_NULL(sf_priority); - - /* bandwidth */ - - sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); - CHECK_NULL(sf_bandwidth); - - /* Initialize the static enum values */ - - sfs_NOSTATUS = getEnumField(env, "NO_STATUS"); - CHECK_NULL(sfs_NOSTATUS); - sfs_OK = getEnumField(env, "OK"); - CHECK_NULL(sfs_OK); - sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION"); - CHECK_NULL(sfs_NOPERMISSION); - sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED"); - CHECK_NULL(sfs_NOTCONNECTED); - sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED"); - CHECK_NULL(sfs_NOTSUPPORTED); - sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED"); - CHECK_NULL(sfs_ALREADYCREATED); - sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS"); - CHECK_NULL(sfs_INPROGRESS); - sfs_OTHER = getEnumField(env, "OTHER"); - CHECK_NULL(sfs_OTHER); - initialized = JNI_TRUE; } -static jobject getEnumField(JNIEnv *env, char *name) +/** Return the Status value. */ +static jint toStatus(int errval) { - jobject f; - jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name, - "Ljdk/net/SocketFlow$Status;"); - CHECK_NULL_RETURN(fID, NULL); + switch (errval) { + case 0: return jdk_net_SocketFlow_OK_VALUE; + case EPERM: return jdk_net_SocketFlow_NO_PERMISSION_VALUE; + case ENOTCONN: return jdk_net_SocketFlow_NOT_CONNECTED_VALUE; + case EOPNOTSUPP: return jdk_net_SocketFlow_NOT_SUPPORTED_VALUE; + case EALREADY: return jdk_net_SocketFlow_ALREADY_CREATED_VALUE; + case EINPROGRESS: return jdk_net_SocketFlow_IN_PROGRESS_VALUE; + default: return jdk_net_SocketFlow_OTHER_VALUE; + } +} - f = (*env)->GetStaticObjectField(env, sf_status_class, fID); - CHECK_NULL_RETURN(f, NULL); - f = (*env)->NewGlobalRef(env, f); - CHECK_NULL_RETURN(f, NULL); - return f; +void throwByNameWithLastError + (JNIEnv *env, const char *name, const char *defaultDetail) +{ + char defaultMsg[255]; + sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail); + JNU_ThrowByNameWithLastError(env, name, defaultMsg); } /* - * Retrieve the int file-descriptor from a public socket type object. - * Gets impl, then the FileDescriptor from the impl, and then the fd - * from that. + * Class: jdk_net_SolarisSocketOptions + * Method: setFlowOption0 + * Signature: (IIJ)I */ -static int getFD(JNIEnv *env, jobject fileDesc) { - return (*env)->GetIntField(env, fileDesc, sf_fd_fdID); -} +JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_setFlowOption + (JNIEnv *env, jobject unused, jint fd, jint priority, jlong bandwidth) +{ + int rv; + sock_flow_props_t props; + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; -/** - * Sets the status field of a SocketFlow to one of the - * canned enum values - */ -static void setStatus (JNIEnv *env, jobject obj, int errval) -{ - switch (errval) { - case 0: /* OK */ - (*env)->SetObjectField(env, obj, sf_status, sfs_OK); - break; - case EPERM: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION); - break; - case ENOTCONN: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED); - break; - case EOPNOTSUPP: - (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED); - break; - case EALREADY: - (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED); - break; - case EINPROGRESS: - (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS); - break; - default: - (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER); - break; + if (priority != jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = priority; } -} + if (bandwidth > jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_MAXBW; + props.sfp_maxbw = (uint64_t) bandwidth; + } -#ifdef __solaris__ + rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); -/* - * Class: sun_net_ExtendedOptionsImpl - * Method: setFlowOption - * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V - */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - int fd = getFD(env, fileDesc); - - if (fd < 0) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); - return; - } else { - sock_flow_props_t props; - jlong bandwidth; - int rv; - - jint priority = (*env)->GetIntField(env, flow, sf_priority); - memset(&props, 0, sizeof(props)); - props.sfp_version = SOCK_FLOW_PROP_VERSION1; - - if (priority != jdk_net_SocketFlow_UNSET) { - props.sfp_mask |= SFP_PRIORITY; - props.sfp_priority = priority; + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else if (errno == EACCES || errno == EPERM) { + JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); + } else { + throwByNameWithLastError(env, "java/net/SocketException", + "set option SO_FLOW_SLA failed"); } - bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth); - if (bandwidth > -1) { - props.sfp_mask |= SFP_MAXBW; - props.sfp_maxbw = (uint64_t) bandwidth; - } - rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); - if (rv < 0) { - if (errno == ENOPROTOOPT) { - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); - } else if (errno == EACCES || errno == EPERM) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "Permission denied"); - } else { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "set option SO_FLOW_SLA failed"); - } - return; - } - setStatus(env, flow, props.sfp_status); + return 0; } + return toStatus(props.sfp_status); } /* - * Class: sun_net_ExtendedOptionsImpl - * Method: getFlowOption - * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V + * Class: jdk_net_SolarisSocketOptions + * Method: getFlowOption0 + * Signature: (ILjdk/net/SocketFlow;)I */ -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_getFlowOption + (JNIEnv *env, jobject unused, jint fd, jobject flow) { - int fd = getFD(env, fileDesc); + sock_flow_props_t props; + socklen_t sz = sizeof(props); - if (fd < 0) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); - return; - } else { - sock_flow_props_t props; - int status; - socklen_t sz = sizeof(props); + int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); - int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); - if (rv < 0) { - if (errno == ENOPROTOOPT) { - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); - } else if (errno == EACCES || errno == EPERM) { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "Permission denied"); - } else { - NET_ERROR(env, JNU_JAVANETPKG "SocketException", - "set option SO_FLOW_SLA failed"); - } - return; + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else if (errno == EACCES || errno == EPERM) { + JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); + } else { + throwByNameWithLastError(env, "java/net/SocketException", + "get option SO_FLOW_SLA failed"); } - /* first check status to see if flow exists */ - status = props.sfp_status; - setStatus(env, flow, status); - if (status == 0) { /* OK */ - /* can set the other fields now */ - if (props.sfp_mask & SFP_PRIORITY) { - (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); - } - if (props.sfp_mask & SFP_MAXBW) { - (*env)->SetLongField(env, flow, sf_bandwidth, - (jlong)props.sfp_maxbw); - } + return -1; + } + /* first check status to see if flow exists */ + if (props.sfp_status == 0) { /* OK */ + /* can set the other fields now */ + if (props.sfp_mask & SFP_PRIORITY) { + (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); + } + if (props.sfp_mask & SFP_MAXBW) { + (*env)->SetLongField(env, flow, sf_bandwidth, + (jlong)props.sfp_maxbw); } } + return toStatus(props.sfp_status); } -static jboolean flowsupported; -static jboolean flowsupported_set = JNI_FALSE; - -static jboolean flowSupported0() +JNIEXPORT jboolean JNICALL Java_jdk_net_SolarisSocketOptions_flowSupported + (JNIEnv *env, jobject unused) { /* Do a simple dummy call, and try to figure out from that */ sock_flow_props_t props; int rv, s; - if (flowsupported_set) { - return flowsupported; - } + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { - flowsupported = JNI_FALSE; - flowsupported_set = JNI_TRUE; return JNI_FALSE; } memset(&props, 0, sizeof(props)); @@ -308,37 +172,5 @@ rv = JNI_TRUE; } close(s); - flowsupported = rv; - flowsupported_set = JNI_TRUE; - return flowsupported; + return rv; } - -#else /* __solaris__ */ - -/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption - (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) -{ - JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", - "unsupported socket option"); -} - -static jboolean flowSupported0() { - return JNI_FALSE; -} - -#endif /* __solaris__ */ - -JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported - (JNIEnv *env, jclass UNUSED) -{ - return flowSupported0(); -} diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h new file mode 100644 --- /dev/null +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +#ifndef SOLARIS_SOCKET_OPTIONS_H +#define SOLARIS_SOCKET_OPTIONS_H + +#include +#include +#include +#include +#include + +#include "jni_util.h" +#include "jdk_net_SocketFlow.h" +#include "SolarisSocketOptions.h" +#include "jdk_net_SolarisSocketOptions.h" + +#ifndef SO_FLOW_SLA +#define SO_FLOW_SLA 0x1018 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack(4) +#endif + +/* + * Used with the setsockopt(SO_FLOW_SLA, ...) call to set + * per socket service level properties. + * When the application uses per-socket API, we will enforce the properties + * on both outbound and inbound packets. + * + * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. + */ +typedef struct sock_flow_props_s { + int sfp_version; + uint32_t sfp_mask; + int sfp_priority; /* flow priority */ + uint64_t sfp_maxbw; /* bandwidth limit in bps */ + int sfp_status; /* flow create status for getsockopt */ +} sock_flow_props_t; + +#define SOCK_FLOW_PROP_VERSION1 1 + +/* bit mask values for sfp_mask */ +#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ +#define SFP_PRIORITY 0x00000008 /* Flow priority */ + +/* possible values for sfp_priority */ +#define SFP_PRIO_NORMAL 1 +#define SFP_PRIO_HIGH 2 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack() +#endif /* _LONG_LONG_ALIGNMENT */ + +#endif /* SO_FLOW_SLA */ + +#endif /* SOLARIS_SOCKET_OPTIONS_H */ diff --git a/src/jdk.policytool/share/classes/module-info.java b/src/jdk.policytool/share/classes/module-info.java --- a/src/jdk.policytool/share/classes/module-info.java +++ b/src/jdk.policytool/share/classes/module-info.java @@ -28,6 +28,7 @@ requires java.logging; requires java.management; requires java.sql; + requires jdk.net; requires java.security.jgss; requires jdk.security.jgss; } diff --git a/test/java/net/SocketOption/OptionsTest.java b/test/java/net/SocketOption/OptionsTest.java --- a/test/java/net/SocketOption/OptionsTest.java +++ b/test/java/net/SocketOption/OptionsTest.java @@ -23,11 +23,13 @@ /* * @test - * @bug 8036979 8072384 + * @bug 8036979 8072384 8044773 * @run main/othervm -Xcheck:jni OptionsTest * @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest + * @run main/othervm -Djdk.launcher.limitmods=java.base OptionsTest */ +import java.lang.reflect.Method; import java.net.*; import java.util.*; @@ -43,7 +45,7 @@ } Object option; Object testValue; - }; + } // The tests set the option using the new API, read back the set value // which could be diferent, and then use the legacy get API to check @@ -223,8 +225,7 @@ } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.IP_TOS)) { - return Integer.valueOf(jdk.net.Sockets.getOption( - socket, StandardSocketOptions.IP_TOS)); + return getServerSocketTrafficClass(socket); } else { throw new RuntimeException("unexecpted socket option"); } @@ -281,4 +282,20 @@ doDgSocketTests(); doMcSocketTests(); } + + // Reflectively access jdk.net.Sockets.getOption so that the test can run + // without the jdk.net module. + static Object getServerSocketTrafficClass(ServerSocket ss) throws Exception { + try { + Class c = Class.forName("jdk.net.Sockets"); + Method m = c.getDeclaredMethod("getOption", ServerSocket.class, SocketOption.class); + return m.invoke(null, ss, StandardSocketOptions.IP_TOS); + } catch (ClassNotFoundException e) { + // Ok, jdk.net module not present, just fall back + System.out.println("jdk.net module not present, falling back."); + return Integer.valueOf(ss.getOption(StandardSocketOptions.IP_TOS)); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } } diff --git a/test/java/net/SocketOption/UnsupportedOptionsTest.java b/test/java/net/SocketOption/UnsupportedOptionsTest.java --- a/test/java/net/SocketOption/UnsupportedOptionsTest.java +++ b/test/java/net/SocketOption/UnsupportedOptionsTest.java @@ -21,34 +21,48 @@ * questions. */ -import jdk.net.ExtendedSocketOptions; - import java.io.IOException; +import java.lang.reflect.Field; import java.net.*; +import java.util.ArrayList; +import java.util.List; /* * @test - * @bug 8143554 - * @run main UnsupportedOptionsTest + * @bug 8143554 8044773 * @summary Test checks that UnsupportedOperationException for unsupported * SOCKET_OPTIONS is thrown by both getOption() and setOption() methods. + * @run main UnsupportedOptionsTest + * @run main/othervm -Djdk.launcher.limitmods=java.base UnsupportedOptionsTest */ + public class UnsupportedOptionsTest { - private static final SocketOption[] SOCKET_OPTIONS = { - StandardSocketOptions.IP_MULTICAST_IF, - StandardSocketOptions.IP_MULTICAST_LOOP, - StandardSocketOptions.IP_MULTICAST_TTL, - StandardSocketOptions.IP_TOS, - StandardSocketOptions.SO_BROADCAST, - StandardSocketOptions.SO_KEEPALIVE, - StandardSocketOptions.SO_LINGER, - StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.SO_SNDBUF, - StandardSocketOptions.TCP_NODELAY, - ExtendedSocketOptions.SO_FLOW_SLA - }; + private static final List> socketOptions = new ArrayList<>(); + + static { + socketOptions.add(StandardSocketOptions.IP_MULTICAST_IF); + socketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP); + socketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL); + socketOptions.add(StandardSocketOptions.IP_TOS); + socketOptions.add(StandardSocketOptions.SO_BROADCAST); + socketOptions.add(StandardSocketOptions.SO_KEEPALIVE); + socketOptions.add(StandardSocketOptions.SO_LINGER); + socketOptions.add(StandardSocketOptions.SO_RCVBUF); + socketOptions.add(StandardSocketOptions.SO_REUSEADDR); + socketOptions.add(StandardSocketOptions.SO_SNDBUF); + socketOptions.add(StandardSocketOptions.TCP_NODELAY); + + try { + Class c = Class.forName("jdk.net.ExtendedSocketOptions"); + Field field = c.getField("SO_FLOW_SLA"); + socketOptions.add((SocketOption)field.get(null)); + } catch (ClassNotFoundException e) { + // ignore, jdk.net module not present + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } public static void main(String[] args) throws IOException { Socket s = new Socket(); @@ -56,7 +70,7 @@ DatagramSocket ds = new DatagramSocket(); MulticastSocket ms = new MulticastSocket(); - for (SocketOption option : SOCKET_OPTIONS) { + for (SocketOption option : socketOptions) { if (!s.supportedOptions().contains(option)) { testUnsupportedSocketOption(s, option); } diff --git a/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java --- a/test/java/nio/channels/DatagramChannel/SocketOptionTests.java +++ b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -22,8 +22,10 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test for setOption/getOption/options methods + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java --- a/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java +++ b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -22,9 +22,11 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test for ServerSocketChannel setOption/getOption/options * methods. + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/test/java/nio/channels/SocketChannel/SocketOptionTests.java --- a/test/java/nio/channels/SocketChannel/SocketOptionTests.java +++ b/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -22,9 +22,11 @@ */ /* @test - * @bug 4640544 + * @bug 4640544 8044773 * @summary Unit test to check SocketChannel setOption/getOption/options * methods. + * @run main SocketOptionTests + * @run main/othervm -Djdk.launcher.limitmods=java.base SocketOptionTests */ import java.nio.*; diff --git a/test/jdk/net/SocketFlow/SocketFlowBasic.java b/test/jdk/net/SocketFlow/SocketFlowBasic.java new file mode 100644 --- /dev/null +++ b/test/jdk/net/SocketFlow/SocketFlowBasic.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, 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 8765432 + * @summary Basic test for SocketFlow API + * @run testng SocketFlowBasic + */ + +import jdk.net.SocketFlow; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static jdk.net.SocketFlow.*; +import static org.testng.Assert.*; + +public class SocketFlowBasic { + + @DataProvider + public Object[][] validPriorities() { + return new Object[][] { {HIGH_PRIORITY}, {NORMAL_PRIORITY} }; + } + + @Test(dataProvider = "validPriorities") + public void priority(long validPriority) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(validPriority); + long bandwidth = flow.bandwidth(); + assertTrue(bandwidth == validPriority, "Expected " + validPriority + ", got" + bandwidth); + } + + @DataProvider + public Object[][] invalidPriorities() { + return new Object[][] { {HIGH_PRIORITY+10}, {NORMAL_PRIORITY-10000} }; + } + + @Test(dataProvider = "invalidPriorities", expectedExceptions = IllegalArgumentException.class) + public void priority(int invalidPriority) { + SocketFlow flow = SocketFlow.create(); + flow.priority(invalidPriority); + } + + @DataProvider + public Object[][] positiveBandwidth() { + return new Object[][] { {0}, {100}, {Integer.MAX_VALUE}, {Long.MAX_VALUE} }; + } + + @Test(dataProvider = "positiveBandwidth") + public void bandwidth(long posBandwidth) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(posBandwidth); + long bandwidth = flow.bandwidth(); + assertTrue(bandwidth == posBandwidth, "Expected " + posBandwidth + ", got" + bandwidth); + } + + + @DataProvider + public Object[][] negativeBandwidth() { + return new Object[][] { {-1}, {-100}, {Integer.MIN_VALUE}, {Long.MIN_VALUE} }; + } + + @Test(dataProvider = "negativeBandwidth", expectedExceptions = IllegalArgumentException.class) + public void invalidBandwidth(long negBandwidth) { + SocketFlow flow = SocketFlow.create(); + flow.bandwidth(negBandwidth); + } + + @Test + public void status() { + SocketFlow flow = SocketFlow.create(); + assertTrue(flow.status() == Status.NO_STATUS); + } +} diff --git a/test/jdk/net/Sockets/Test.java b/test/jdk/net/Sockets/Test.java --- a/test/jdk/net/Sockets/Test.java +++ b/test/jdk/net/Sockets/Test.java @@ -23,8 +23,9 @@ /* * @test - * @bug 8032808 - * @run main/othervm -Xcheck:jni Test + * @bug 8032808 8044773 + * @modules jdk.net + * @run main/othervm -Xcheck:jni Test success * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail * @run main/othervm/policy=policy.success -Xcheck:jni Test success */ @@ -35,15 +36,13 @@ import java.util.concurrent.*; import java.util.Set; import jdk.net.*; +import static java.lang.System.out; public class Test { - static boolean security; - static boolean success; + interface Runner { void run() throws Exception; } - interface Runner { - public void run() throws Exception; - } + static boolean expectSuccess; public static void main(String[] args) throws Exception { @@ -52,95 +51,107 @@ Sockets.supportedOptions(Socket.class); - security = System.getSecurityManager() != null; - success = security && args[0].equals("success"); + expectSuccess = args[0].equals("success"); // Main thing is to check for JNI problems // Doesn't matter if current system does not support the option // and currently setting the option with the loopback interface // doesn't work either - System.out.println ("Security Manager enabled: " + security); - if (security) { - System.out.println ("Success expected: " + success); + boolean sm = System.getSecurityManager() != null; + out.println("Security Manager enabled: " + sm); + out.println("Success expected: " + expectSuccess); + + SocketFlow flowIn = SocketFlow.create() + .bandwidth(1000) + .priority(SocketFlow.HIGH_PRIORITY); + + try (ServerSocket ss = new ServerSocket(0); + DatagramSocket dg = new DatagramSocket(0)) { + + int tcp_port = ss.getLocalPort(); + final InetAddress loop = InetAddress.getByName("127.0.0.1"); + final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); + + final int udp_port = dg.getLocalPort(); + + // If option not available, end test + Set> options = dg.supportedOptions(); + if (!options.contains(ExtendedSocketOptions.SO_FLOW_SLA)) { + System.out.println("SO_FLOW_SLA not supported"); + return; + } + + final Socket s = new Socket("127.0.0.1", tcp_port); + final SocketChannel sc = SocketChannel.open(); + sc.connect(new InetSocketAddress("127.0.0.1", tcp_port)); + + doTest("Sockets.setOption Socket", () -> { + out.println(flowIn); + Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + out.println(flowIn); + }); + doTest("Sockets.getOption Socket",() -> { + Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); + out.println(flowIn); + }); + doTest("Sockets.setOption SocketChannel",() -> + sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn) + ); + doTest("Sockets.getOption SocketChannel",() -> + sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA) + ); + doTest("Sockets.setOption DatagramSocket",() -> { + try (DatagramSocket dg1 = new DatagramSocket(0)) { + dg1.connect(loop, udp_port); + Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption DatagramSocket 2", () -> { + try (DatagramChannel dg2 = DatagramChannel.open()) { + dg2.bind(new InetSocketAddress(loop, 0)); + dg2.connect(new InetSocketAddress(loop, udp_port)); + dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption MulticastSocket", () -> { + try (MulticastSocket mc1 = new MulticastSocket(0)) { + mc1.connect(loop, udp_port); + Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); + doTest("Sockets.setOption AsynchronousSocketChannel", () -> { + try (AsynchronousSocketChannel asc = AsynchronousSocketChannel.open()) { + Future f = asc.connect(loopad); + f.get(); + asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + } + }); } - - final SocketFlow flowIn = SocketFlow.create() - .bandwidth(1000) - .priority(SocketFlow.HIGH_PRIORITY); - - ServerSocket ss = new ServerSocket(0); - int tcp_port = ss.getLocalPort(); - final InetAddress loop = InetAddress.getByName("127.0.0.1"); - final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); - - DatagramSocket dg = new DatagramSocket(0); - final int udp_port = dg.getLocalPort(); - - // If option not available, end test - Set> options = dg.supportedOptions(); - if (!options.contains(ExtendedSocketOptions.SO_FLOW_SLA)) { - System.out.println("SO_FLOW_SLA not supported"); - return; - } - - final Socket s = new Socket("127.0.0.1", tcp_port); - final SocketChannel sc = SocketChannel.open(); - sc.connect (new InetSocketAddress("127.0.0.1", tcp_port)); - - doTest(()->{ - Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); - }); - doTest(()->{ - sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA); - }); - doTest(()->{ - DatagramSocket dg1 = new DatagramSocket(0); - dg1.connect(loop, udp_port); - Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - DatagramChannel dg2 = DatagramChannel.open(); - dg2.bind(new InetSocketAddress(loop, 0)); - dg2.connect(new InetSocketAddress(loop, udp_port)); - dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - MulticastSocket mc1 = new MulticastSocket(0); - mc1.connect(loop, udp_port); - Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); - doTest(()->{ - AsynchronousSocketChannel asc = AsynchronousSocketChannel.open(); - Future f = asc.connect(loopad); - f.get(); - asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); - }); } - static void doTest(Runner func) throws Exception { + static void doTest(String message, Runner func) throws Exception { + out.println(message); try { func.run(); - if (security && !success) { - throw new RuntimeException("Test failed"); + if (expectSuccess) { + out.println("Completed as expected"); + } else { + throw new RuntimeException("Operation succeeded, but expected SecurityException"); } } catch (SecurityException e) { - if (success) { - throw new RuntimeException("Test failed"); + if (expectSuccess) { + throw new RuntimeException("Unexpected SecurityException", e); + } else { + out.println("Caught expected: " + e); } } catch (UnsupportedOperationException e) { - System.out.println (e); + System.out.println(e); } catch (IOException e) { // Probably a permission error, but we're not // going to check unless a specific permission exception // is defined. - System.out.println (e); + System.out.println(e); } } }