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;
+ }
+ }
}