src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java

Print this page
rev 14282 : 8044773: Refactor jdk.net API so that it can be moved out of the base module
Reviewed-by:

*** 23,33 **** --- 23,41 ---- * questions. */ 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 * {@link java.net.StandardSocketOptions}. These options may be platform * specific.
*** 46,61 **** @Override public String name() { return name; } @Override public Class<T> type() { return type; } @Override public String toString() { return name; } } ! private ExtendedSocketOptions() {} /** * Service level properties. When a security manager is installed, * setting or getting this option requires a {@link NetworkPermission} * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} * respectively. */ public static final SocketOption<SocketFlow> SO_FLOW_SLA = new ExtSocketOption<SocketFlow>("SO_FLOW_SLA", SocketFlow.class); } --- 54,212 ---- @Override public String name() { return name; } @Override public Class<T> type() { return type; } @Override public String toString() { return name; } } ! private ExtendedSocketOptions() { } /** * Service level properties. When a security manager is installed, * setting or getting this option requires a {@link NetworkPermission} * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} * respectively. */ public static final SocketOption<SocketFlow> SO_FLOW_SLA = new ExtSocketOption<SocketFlow>("SO_FLOW_SLA", SocketFlow.class); + + + private static final PlatformSocketOptions platformSocketOptions = + PlatformSocketOptions.get(); + + private static final boolean flowSupported = + platformSocketOptions.flowSupported(); + + private static final Set<SocketOption<?>> extendedOptions = options(); + + static Set<SocketOption<?>> options() { + if (flowSupported) + return Set.of(SO_FLOW_SLA); + else + return Collections.unmodifiableSet(Collections.<SocketOption<?>>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> 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<PlatformSocketOptions> c; + try { + c = (Class<PlatformSocketOptions>)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<String>() { + 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; + } + } }