8032808: Support Solaris SO_FLOW_SLA socket option
Reviewed-by: alanb, chegar
diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers
index a28a3d0..1b6a148 100644
--- a/jdk/make/mapfiles/libnet/mapfile-vers
+++ b/jdk/make/mapfiles/libnet/mapfile-vers
@@ -94,6 +94,10 @@
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/jdk/src/share/classes/java/net/DatagramSocket.java b/jdk/src/share/classes/java/net/DatagramSocket.java
index 1e095de..54799a8 100644
--- a/jdk/src/share/classes/java/net/DatagramSocket.java
+++ b/jdk/src/share/classes/java/net/DatagramSocket.java
@@ -315,6 +315,7 @@
}
// creates a udp socket
impl.create();
+ impl.setDatagramSocket(this);
created = true;
}
diff --git a/jdk/src/share/classes/java/net/DatagramSocketImpl.java b/jdk/src/share/classes/java/net/DatagramSocketImpl.java
index 524f06b..c2b1158 100644
--- a/jdk/src/share/classes/java/net/DatagramSocketImpl.java
+++ b/jdk/src/share/classes/java/net/DatagramSocketImpl.java
@@ -48,6 +48,20 @@
protected FileDescriptor fd;
/**
+ * The DatagramSocket or MulticastSocket
+ * that owns this impl
+ */
+ DatagramSocket socket;
+
+ void setDatagramSocket(DatagramSocket socket) {
+ this.socket = socket;
+ }
+
+ DatagramSocket getDatagramSocket() {
+ return socket;
+ }
+
+ /**
* Creates a datagram socket.
* @exception SocketException if there is an error in the
* underlying protocol, such as a TCP error.
@@ -233,6 +247,56 @@
return localPort;
}
+ <T> void setOption(SocketOption<T> name, T value) throws IOException {
+ if (name == StandardSocketOptions.SO_SNDBUF) {
+ setOption(SocketOptions.SO_SNDBUF, value);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ setOption(SocketOptions.SO_RCVBUF, value);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ setOption(SocketOptions.SO_REUSEADDR, value);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ setOption(SocketOptions.IP_TOS, value);
+ } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ setOption(SocketOptions.IP_MULTICAST_IF2, value);
+ } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ if (! (value instanceof Integer)) {
+ throw new IllegalArgumentException("not an integer");
+ }
+ setTimeToLive((Integer)value);
+ } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ setOption(SocketOptions.IP_MULTICAST_LOOP, value);
+ } else {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+ }
+
+ <T> T getOption(SocketOption<T> name) throws IOException {
+ if (name == StandardSocketOptions.SO_SNDBUF) {
+ return (T) getOption(SocketOptions.SO_SNDBUF);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ return (T) getOption(SocketOptions.SO_RCVBUF);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ return (T) getOption(SocketOptions.SO_REUSEADDR);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ return (T) getOption(SocketOptions.IP_TOS);
+ } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ return (T) getOption(SocketOptions.IP_MULTICAST_IF2);
+ } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ Integer ttl = getTimeToLive();
+ return (T)ttl;
+ } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+ (getDatagramSocket() instanceof MulticastSocket)) {
+ return (T) getOption(SocketOptions.IP_MULTICAST_LOOP);
+ } else {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+ }
+
/**
* Gets the datagram socket file descriptor.
* @return a {@code FileDescriptor} object representing the datagram socket
diff --git a/jdk/src/share/classes/java/net/SocketImpl.java b/jdk/src/share/classes/java/net/SocketImpl.java
index 67286a1..223e3cc 100644
--- a/jdk/src/share/classes/java/net/SocketImpl.java
+++ b/jdk/src/share/classes/java/net/SocketImpl.java
@@ -355,4 +355,44 @@
{
/* Not implemented yet */
}
+
+ <T> void setOption(SocketOption<T> name, T value) throws IOException {
+ if (name == StandardSocketOptions.SO_KEEPALIVE) {
+ setOption(SocketOptions.SO_KEEPALIVE, value);
+ } else if (name == StandardSocketOptions.SO_SNDBUF) {
+ setOption(SocketOptions.SO_SNDBUF, value);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ setOption(SocketOptions.SO_RCVBUF, value);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ setOption(SocketOptions.SO_REUSEADDR, value);
+ } else if (name == StandardSocketOptions.SO_LINGER) {
+ setOption(SocketOptions.SO_LINGER, value);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ setOption(SocketOptions.IP_TOS, value);
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ setOption(SocketOptions.TCP_NODELAY, value);
+ } else {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+ }
+
+ <T> T getOption(SocketOption<T> name) throws IOException {
+ if (name == StandardSocketOptions.SO_KEEPALIVE) {
+ return (T)getOption(SocketOptions.SO_KEEPALIVE);
+ } else if (name == StandardSocketOptions.SO_SNDBUF) {
+ return (T)getOption(SocketOptions.SO_SNDBUF);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ return (T)getOption(SocketOptions.SO_RCVBUF);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ return (T)getOption(SocketOptions.SO_REUSEADDR);
+ } else if (name == StandardSocketOptions.SO_LINGER) {
+ return (T)getOption(SocketOptions.SO_LINGER);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ return (T)getOption(SocketOptions.IP_TOS);
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ return (T)getOption(SocketOptions.TCP_NODELAY);
+ } else {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+ }
}
diff --git a/jdk/src/share/classes/java/net/SocketSecrets.java b/jdk/src/share/classes/java/net/SocketSecrets.java
new file mode 100644
index 0000000..9772906
--- /dev/null
+++ b/jdk/src/share/classes/java/net/SocketSecrets.java
@@ -0,0 +1,70 @@
+/*
+ * 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 java.net;
+
+import java.io.IOException;
+
+class SocketSecrets {
+
+ /* accessed by reflection from jdk.net.Sockets */
+
+ /* obj must be a Socket or ServerSocket */
+
+ private static <T> void setOption(Object obj, SocketOption<T> name, T value) throws IOException {
+ SocketImpl impl;
+
+ if (obj instanceof Socket) {
+ impl = ((Socket)obj).getImpl();
+ } else if (obj instanceof ServerSocket) {
+ impl = ((ServerSocket)obj).getImpl();
+ } else {
+ throw new IllegalArgumentException();
+ }
+ impl.setOption(name, value);
+ }
+
+ private static <T> T getOption(Object obj, SocketOption<T> name) throws IOException {
+ SocketImpl impl;
+
+ if (obj instanceof Socket) {
+ impl = ((Socket)obj).getImpl();
+ } else if (obj instanceof ServerSocket) {
+ impl = ((ServerSocket)obj).getImpl();
+ } else {
+ throw new IllegalArgumentException();
+ }
+ return impl.getOption(name);
+ }
+
+ private static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException {
+ s.getImpl().setOption(name, value);
+ }
+
+ private static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException {
+ return s.getImpl().getOption(name);
+ }
+
+}
diff --git a/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java
new file mode 100644
index 0000000..8be1fe6
--- /dev/null
+++ b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java
@@ -0,0 +1,62 @@
+/*
+ * 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 jdk.net;
+
+import java.net.SocketOption;
+
+/**
+ * Defines extended socket options, beyond those defined in
+ * {@link java.net.StandardSocketOptions}. These options may be platform
+ * specific.
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public final class ExtendedSocketOptions {
+
+ private static class ExtSocketOption<T> implements SocketOption<T> {
+ private final String name;
+ private final Class<T> type;
+ ExtSocketOption(String name, Class<T> type) {
+ this.name = name;
+ this.type = type;
+ }
+ @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);
+}
diff --git a/jdk/src/share/classes/jdk/net/NetworkPermission.java b/jdk/src/share/classes/jdk/net/NetworkPermission.java
new file mode 100644
index 0000000..9020273
--- /dev/null
+++ b/jdk/src/share/classes/jdk/net/NetworkPermission.java
@@ -0,0 +1,91 @@
+/*
+ * 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 jdk.net;
+
+import java.security.BasicPermission;
+
+/**
+ * Represents permission to access the extended networking capabilities
+ * defined in the jdk.net package. These permissions contain a target
+ * name, but no actions list. Callers either possess the permission or not.
+ * <p>
+ * The following targets are defined:
+ * <p>
+ * <table border=1 cellpadding=5 summary="permission target name,
+ * what the target allows,and associated risks">
+ * <tr>
+ * <th>Permission Target Name</th>
+ * <th>What the Permission Allows</th>
+ * <th>Risks of Allowing this Permission</th>
+ * </tr>
+ * <tr>
+ * <td>setOption.SO_FLOW_SLA</td>
+ * <td>set the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} option
+ * on any socket that supports it</td>
+ * <td>allows caller to set a higher priority or bandwidth allocation
+ * to sockets it creates, than they might otherwise be allowed.</td>
+ * </tr>
+ * <tr>
+ * <td>getOption.SO_FLOW_SLA</td>
+ * <td>retrieve the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA}
+ * setting from any socket that supports the option</td>
+ * <td>allows caller access to SLA information that it might not
+ * otherwise have</td>
+ * </tr></table>
+ *
+ * @see jdk.net.ExtendedSocketOptions
+ *
+ * @since 1.9
+ */
+
+@jdk.Exported
+public final class NetworkPermission extends BasicPermission {
+
+ private static final long serialVersionUID = -2012939586906722291L;
+
+ /**
+ * Creates a NetworkPermission with the given target name.
+ *
+ * @param name the permission target name
+ * @throws NullPointerException if {@code name} is {@code null}.
+ * @throws IllegalArgumentException if {@code name} is empty.
+ */
+ public NetworkPermission(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a NetworkPermission with the given target name.
+ *
+ * @param name the permission target name
+ * @param actions should be {@code null}. Is ignored if not.
+ * @throws NullPointerException if {@code name} is {@code null}.
+ * @throws IllegalArgumentException if {@code name} is empty.
+ */
+ public NetworkPermission(String name, String actions) {
+ super(name, actions);
+ }
+}
diff --git a/jdk/src/share/classes/jdk/net/SocketFlow.java b/jdk/src/share/classes/jdk/net/SocketFlow.java
new file mode 100644
index 0000000..a102a3f
--- /dev/null
+++ b/jdk/src/share/classes/jdk/net/SocketFlow.java
@@ -0,0 +1,169 @@
+/*
+ * 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 jdk.net;
+
+import java.lang.annotation.Native;
+
+/**
+ * Represents the service level properties for the platform specific socket
+ * option {@link ExtendedSocketOptions#SO_FLOW_SLA}.
+ * <p>
+ * The priority and bandwidth parameters must be set before
+ * setting the socket option.
+ * <p>
+ * When the {@code SO_FLOW_SLA} option is set then it may not take effect
+ * immediately. If the value of the socket option is obtained with
+ * {@code getOption()} then the status may be returned as {@code INPROGRESS}
+ * until it takes effect. The priority and bandwidth values are only valid when
+ * the status is returned as OK.
+ * <p>
+ * When a security manager is installed, a {@link NetworkPermission}
+ * is required to set or get this option.
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public class SocketFlow {
+
+ private 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() {}
+
+ /**
+ * Enumeration of the return values from the SO_FLOW_SLA
+ * socket option. Both setting and getting the option return
+ * one of these statuses, which reflect the state of socket's
+ * flow.
+ *
+ * @since 1.9
+ */
+ @jdk.Exported
+ public enum Status {
+ /**
+ * Set or get socket option has not been called yet. Status
+ * values can only be retrieved after calling set or get.
+ */
+ NO_STATUS,
+ /**
+ * Flow successfully created.
+ */
+ OK,
+ /**
+ * Caller has no permission to create flow.
+ */
+ NO_PERMISSION,
+ /**
+ * Flow can not be created because socket is not connected.
+ */
+ NOT_CONNECTED,
+ /**
+ * Flow creation not supported for this socket.
+ */
+ NOT_SUPPORTED,
+ /**
+ * A flow already exists with identical attributes.
+ */
+ ALREADY_CREATED,
+ /**
+ * A flow is being created.
+ */
+ IN_PROGRESS,
+ /**
+ * Some other unspecified error.
+ */
+ OTHER
+ }
+
+ /**
+ * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA
+ * socket option and create a socket flow.
+ */
+ public static SocketFlow create() {
+ return new SocketFlow();
+ }
+
+ /**
+ * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY
+ * HIGH_PRIORITY. If not set, a flow's priority is normal.
+ *
+ * @throws IllegalArgumentException if priority is not NORMAL_PRIORITY or
+ * HIGH_PRIORITY.
+ */
+ public SocketFlow priority(int priority) {
+ if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) {
+ throw new IllegalArgumentException("invalid priority");
+ }
+ this.priority = priority;
+ return this;
+ }
+
+ /**
+ * Sets this SocketFlow's bandwidth. Must be greater than or equal to zero.
+ * A value of zero drops all packets for the socket.
+ *
+ * @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;
+ }
+ return this;
+ }
+
+ /**
+ * Returns this SocketFlow's priority.
+ */
+ public int priority() {
+ return priority;
+ }
+
+ /**
+ * Returns this SocketFlow's bandwidth.
+ *
+ * @return this SocketFlow's bandwidth, or {@code -1} if status is not OK.
+ */
+ public long bandwidth() {
+ return bandwidth;
+ }
+
+ /**
+ * Returns the Status value of this SocketFlow. NO_STATUS is returned
+ * if the object was not used in a call to set or get the option.
+ */
+ public Status status() {
+ return status;
+ }
+}
diff --git a/jdk/src/share/classes/jdk/net/Sockets.java b/jdk/src/share/classes/jdk/net/Sockets.java
new file mode 100644
index 0000000..8362fc6
--- /dev/null
+++ b/jdk/src/share/classes/jdk/net/Sockets.java
@@ -0,0 +1,402 @@
+/*
+ * 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 jdk.net;
+
+import java.net.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.lang.reflect.*;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Collections;
+import sun.net.ExtendedOptionsImpl;
+
+/**
+ * Defines static methods to set and get socket options defined by the
+ * {@link java.net.SocketOption} interface. All of the standard options defined
+ * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and
+ * {@link java.net.DatagramSocket} can be set this way, as well as additional
+ * or platform specific options supported by each socket type.
+ * <p>
+ * The {@link #supportedOptions(Class)} method can be called to determine
+ * the complete set of options available (per socket type) on the
+ * current system.
+ * <p>
+ * When a security manager is installed, some non-standard socket options
+ * may require a security permission before being set or get.
+ * The details are specified in {@link ExtendedSocketOptions}. No permission
+ * is required for {@link java.net.StandardSocketOption}s.
+ *
+ * @see java.nio.channels.NetworkChannel
+ */
+@jdk.Exported
+public class Sockets {
+
+ private final static HashMap<Class<?>,Set<SocketOption<?>>>
+ options = new HashMap<>();
+
+ static {
+ initOptionSets();
+ AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ initMethods();
+ return null;
+ }
+ }
+ );
+ }
+
+ private static Method siSetOption;
+ private static Method siGetOption;
+ private static Method dsiSetOption;
+ private static Method dsiGetOption;
+
+ private static void initMethods() {
+ try {
+ Class<?> clazz = Class.forName("java.net.SocketSecrets");
+
+ siSetOption = clazz.getDeclaredMethod(
+ "setOption", Object.class,
+ SocketOption.class, Object.class
+ );
+ siSetOption.setAccessible(true);
+
+ siGetOption = clazz.getDeclaredMethod(
+ "getOption", Object.class, SocketOption.class
+ );
+ siGetOption.setAccessible(true);
+
+ dsiSetOption = clazz.getDeclaredMethod(
+ "setOption", DatagramSocket.class,
+ SocketOption.class, Object.class
+ );
+ dsiSetOption.setAccessible(true);
+
+ dsiGetOption = clazz.getDeclaredMethod(
+ "getOption", DatagramSocket.class, SocketOption.class
+ );
+ dsiGetOption.setAccessible(true);
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ private static <T> void invokeSet(
+ Method method, Object socket,
+ SocketOption<T> option, T value) throws IOException
+ {
+ try {
+ method.invoke(null, socket, option, value);
+ } catch (Exception e) {
+ if (e instanceof InvocationTargetException) {
+ Throwable t = ((InvocationTargetException)e).getTargetException();
+ if (t instanceof IOException) {
+ throw (IOException)t;
+ }
+ }
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static <T> T invokeGet(
+ Method method, Object socket, SocketOption<T> option) throws IOException
+ {
+ try {
+ return (T)method.invoke(null, socket, option);
+ } catch (Exception e) {
+ if (e instanceof InvocationTargetException) {
+ Throwable t = ((InvocationTargetException)e).getTargetException();
+ if (t instanceof IOException) {
+ throw (IOException)t;
+ }
+ }
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Sockets() {}
+
+ /**
+ * Sets the value of a socket option on a {@link java.net.Socket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ * @param value The value of the socket option. May be null for some
+ * options.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IllegalArgumentException if the value is not valid for
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs, or socket is closed.
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> void setOption(Socket s, SocketOption<T> name, T value) throws IOException
+ {
+ if (!isSupported(Socket.class, name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ invokeSet(siSetOption, s, name, value);
+ }
+
+ /**
+ * Returns the value of a socket option from a {@link java.net.Socket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ *
+ * @return The value of the socket option.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> T getOption(Socket s, SocketOption<T> name) throws IOException
+ {
+ if (!isSupported(Socket.class, name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ return invokeGet(siGetOption, s, name);
+ }
+
+ /**
+ * Sets the value of a socket option on a {@link java.net.ServerSocket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ * @param value The value of the socket option.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IllegalArgumentException if the value is not valid for
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> void setOption(ServerSocket s, SocketOption<T> name, T value) throws IOException
+ {
+ if (!isSupported(ServerSocket.class, name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ invokeSet(siSetOption, s, name, value);
+ }
+
+ /**
+ * Returns the value of a socket option from a {@link java.net.ServerSocket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ *
+ * @return The value of the socket option.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> T getOption(ServerSocket s, SocketOption<T> name) throws IOException
+ {
+ if (!isSupported(ServerSocket.class, name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ return invokeGet(siGetOption, s, name);
+ }
+
+ /**
+ * Sets the value of a socket option on a {@link java.net.DatagramSocket}
+ * or {@link java.net.MulticastSocket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ * @param value The value of the socket option.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IllegalArgumentException if the value is not valid for
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException
+ {
+ if (!isSupported(s.getClass(), name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ invokeSet(dsiSetOption, s, name, value);
+ }
+
+ /**
+ * Returns the value of a socket option from a
+ * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket}
+ *
+ * @param s the socket
+ * @param name The socket option
+ *
+ * @return The value of the socket option.
+ *
+ * @throws UnsupportedOperationException if the socket does not support
+ * the option.
+ *
+ * @throws IOException if an I/O error occurs
+ *
+ * @throws NullPointerException if name is null
+ *
+ * @throws SecurityException if a security manager is set and the
+ * caller does not have any required permission.
+ *
+ * @see java.net.StandardSocketOptions
+ */
+ public static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException
+ {
+ if (!isSupported(s.getClass(), name)) {
+ throw new UnsupportedOperationException(name.name());
+ }
+ return invokeGet(dsiGetOption, s, name);
+ }
+
+ /**
+ * Returns a set of {@link java.net.SocketOption}s supported by the
+ * given socket type. This set may include standard options and also
+ * non standard extended options.
+ *
+ * @param socketType the type of java.net socket
+ *
+ * @throws IllegalArgumentException if socketType is not a valid
+ * socket type from the java.net package.
+ */
+ public static Set<SocketOption<?>> supportedOptions(Class<?> socketType) {
+ Set<SocketOption<?>> set = options.get(socketType);
+ if (set == null) {
+ throw new IllegalArgumentException("unknown socket type");
+ }
+ return set;
+ }
+
+ private static boolean isSupported(Class<?> type, SocketOption<?> option) {
+ Set<SocketOption<?>> options = supportedOptions(type);
+ return options.contains(option);
+ }
+
+ private static void initOptionSets() {
+ boolean flowsupported = ExtendedOptionsImpl.flowSupported();
+
+ // Socket
+
+ Set<SocketOption<?>> set = new HashSet<>();
+ set.add(StandardSocketOptions.SO_KEEPALIVE);
+ set.add(StandardSocketOptions.SO_SNDBUF);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.SO_LINGER);
+ set.add(StandardSocketOptions.IP_TOS);
+ set.add(StandardSocketOptions.TCP_NODELAY);
+ if (flowsupported) {
+ set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+ }
+ set = Collections.unmodifiableSet(set);
+ options.put(Socket.class, set);
+
+ // ServerSocket
+
+ set = new HashSet<>();
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set = Collections.unmodifiableSet(set);
+ options.put(ServerSocket.class, set);
+
+ // DatagramSocket
+
+ set = new HashSet<>();
+ set.add(StandardSocketOptions.SO_SNDBUF);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.IP_TOS);
+ if (flowsupported) {
+ set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+ }
+ set = Collections.unmodifiableSet(set);
+ options.put(DatagramSocket.class, set);
+
+ // MulticastSocket
+
+ set = new HashSet<>();
+ set.add(StandardSocketOptions.SO_SNDBUF);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.IP_TOS);
+ set.add(StandardSocketOptions.IP_MULTICAST_IF);
+ set.add(StandardSocketOptions.IP_MULTICAST_TTL);
+ set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
+ if (flowsupported) {
+ set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+ }
+ set = Collections.unmodifiableSet(set);
+ options.put(MulticastSocket.class, set);
+ }
+}
diff --git a/jdk/src/share/classes/jdk/net/package-info.java b/jdk/src/share/classes/jdk/net/package-info.java
new file mode 100644
index 0000000..236d640
--- /dev/null
+++ b/jdk/src/share/classes/jdk/net/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/**
+ * Platform specific socket options for the {@code java.net} and {@code java.nio.channels}
+ * socket classes.
+ *
+ * @since 1.9
+ */
+
+@jdk.Exported
+package jdk.net;
diff --git a/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java
new file mode 100644
index 0000000..8fbcdd7
--- /dev/null
+++ b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java
@@ -0,0 +1,92 @@
+/*
+ * 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<Void>)() -> {
+ 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/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
index d28bf90..9899d75 100644
--- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
@@ -39,6 +39,7 @@
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import sun.net.NetHooks;
+import sun.net.ExtendedOptionsImpl;
/**
* Base implementation of AsynchronousSocketChannel
@@ -508,6 +509,9 @@
set.add(StandardSocketOptions.SO_KEEPALIVE);
set.add(StandardSocketOptions.SO_REUSEADDR);
set.add(StandardSocketOptions.TCP_NODELAY);
+ if (ExtendedOptionsImpl.flowSupported()) {
+ set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
+ }
return Collections.unmodifiableSet(set);
}
}
diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
index c151afe..fe32f63 100644
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
@@ -33,6 +33,7 @@
import java.nio.channels.spi.*;
import java.util.*;
import sun.net.ResourceManager;
+import sun.net.ExtendedOptionsImpl;
/**
* An implementation of DatagramChannels.
@@ -317,6 +318,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);
+ }
return Collections.unmodifiableSet(set);
}
}
diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java
index 79ebb2f..753e541 100644
--- a/jdk/src/share/classes/sun/nio/ch/Net.java
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java
@@ -27,11 +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 java.security.PrivilegedExceptionAction;
+import sun.net.ExtendedOptionsImpl;
public class Net {
@@ -297,6 +299,16 @@
// 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);
+ return;
+ }
+
if (type != Integer.class && type != Boolean.class)
throw new AssertionError("Should not reach here");
@@ -349,6 +361,16 @@
{
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;
+ }
+
// only simple values supported by this method
if (type != Integer.class && type != Boolean.class)
throw new AssertionError("Should not reach here");
diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
index a977ced..1e36aed 100644
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
@@ -33,6 +33,7 @@
import java.nio.channels.spi.*;
import java.util.*;
import sun.net.NetHooks;
+import sun.net.ExtendedOptionsImpl;
/**
@@ -237,6 +238,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);
+ }
return Collections.unmodifiableSet(set);
}
}
diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h
index d3b90a9..246c054 100644
--- a/jdk/src/share/native/java/net/net_util.h
+++ b/jdk/src/share/native/java/net/net_util.h
@@ -40,7 +40,7 @@
#define IPv6 2
#define NET_ERROR(env, ex, msg) \
-{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg) }
+{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); }
/************************************************************************
* Cached field IDs
diff --git a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
index 20bc6fb..1f5eca7 100644
--- a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
+++ b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
@@ -25,6 +25,11 @@
package java.net;
import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import jdk.net.*;
+import static sun.net.ExtendedOptionsImpl.*;
/*
* On Unix systems we simply delegate to native methods.
@@ -38,6 +43,32 @@
init();
}
+ protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+ super.setOption(name, value);
+ } else {
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+ checkSetOptionPermission(name);
+ checkValueType(value, SocketFlow.class);
+ setFlowOption(getFileDescriptor(), (SocketFlow)value);
+ }
+ }
+
+ protected <T> T getOption(SocketOption<T> name) throws IOException {
+ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+ return super.getOption(name);
+ }
+ if (isClosed()) {
+ throw new SocketException("Socket closed");
+ }
+ checkGetOptionPermission(name);
+ SocketFlow flow = SocketFlow.create();
+ getFlowOption(getFileDescriptor(), flow);
+ return (T)flow;
+ }
+
protected synchronized native void bind0(int lport, InetAddress laddr)
throws SocketException;
diff --git a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java
index 4846689a..1f634ea 100644
--- a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java
+++ b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java
@@ -26,6 +26,12 @@
import java.io.IOException;
import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import jdk.net.*;
+
+import static sun.net.ExtendedOptionsImpl.*;
/*
* On Unix systems we simply delegate to native methods.
@@ -51,6 +57,32 @@
this.fd = fd;
}
+ protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+ super.setOption(name, value);
+ } else {
+ if (isClosedOrPending()) {
+ throw new SocketException("Socket closed");
+ }
+ checkSetOptionPermission(name);
+ checkValueType(value, SocketFlow.class);
+ setFlowOption(getFileDescriptor(), (SocketFlow)value);
+ }
+ }
+
+ protected <T> T getOption(SocketOption<T> name) throws IOException {
+ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+ return super.getOption(name);
+ }
+ if (isClosedOrPending()) {
+ throw new SocketException("Socket closed");
+ }
+ checkGetOptionPermission(name);
+ SocketFlow flow = SocketFlow.create();
+ getFlowOption(getFileDescriptor(), flow);
+ return (T)flow;
+ }
+
native void socketCreate(boolean isServer) throws IOException;
native void socketConnect(InetAddress address, int port, int timeout)
@@ -77,5 +109,4 @@
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
native void socketSendUrgentData(int data) throws IOException;
-
}
diff --git a/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c
new file mode 100644
index 0000000..145d166
--- /dev/null
+++ b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c
@@ -0,0 +1,329 @@
+/*
+ * 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 <jni.h>
+#include <string.h>
+
+#include "net_util.h"
+#include "jdk_net_SocketFlow.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() ;
+
+/*
+ * Class: sun_net_ExtendedOptionsImpl
+ * Method: init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init
+ (JNIEnv *env, jclass UNUSED) {
+
+ static int initialized = 0;
+ jclass c;
+
+ /* Global class references */
+
+ if (initialized) {
+ return;
+ }
+
+ 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");
+
+ /* 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) {
+ jobject f;
+ jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name,
+ "Ljdk/net/SocketFlow$Status;");
+ CHECK_NULL_RETURN(fID, NULL);
+
+ 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;
+}
+
+/*
+ * 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.
+ */
+static int getFD(JNIEnv *env, jobject fileDesc) {
+ return (*env)->GetIntField(env, fileDesc, sf_fd_fdID);
+}
+
+/**
+ * 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;
+ }
+}
+
+#ifdef __solaris__
+
+/*
+ * 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;
+ }
+ 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 {
+ NET_ERROR(env, JNU_JAVANETPKG "SocketException",
+ "set option SO_FLOW_SLA failed");
+ }
+ return;
+ }
+ setStatus(env, flow, props.sfp_status);
+ }
+}
+
+/*
+ * Class: sun_net_ExtendedOptionsImpl
+ * Method: getFlowOption
+ * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
+ (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;
+ int status;
+ socklen_t sz = sizeof(props);
+
+ 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 {
+ NET_ERROR(env, JNU_JAVANETPKG "SocketException",
+ "set option SO_FLOW_SLA failed");
+ }
+ return;
+ }
+ /* 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);
+ }
+ }
+ }
+}
+
+static jboolean flowsupported;
+static jboolean flowsupported_set = JNI_FALSE;
+
+static jboolean flowSupported0() {
+ /* 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));
+ props.sfp_version = SOCK_FLOW_PROP_VERSION1;
+ props.sfp_mask |= SFP_PRIORITY;
+ props.sfp_priority = SFP_PRIO_NORMAL;
+ rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
+ if (rv != 0 && errno == ENOPROTOOPT) {
+ rv = JNI_FALSE;
+ } else {
+ rv = JNI_TRUE;
+ }
+ close(s);
+ flowsupported = rv;
+ flowsupported_set = JNI_TRUE;
+ return flowsupported;
+}
+
+#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/jdk/src/solaris/native/java/net/net_util_md.h b/jdk/src/solaris/native/java/net/net_util_md.h
index c602753..68c10d6 100644
--- a/jdk/src/solaris/native/java/net/net_util_md.h
+++ b/jdk/src/solaris/native/java/net/net_util_md.h
@@ -93,7 +93,46 @@
#ifdef __solaris__
extern int net_getParam(char *driver, char *param);
-#endif
+
+#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__ */
/* needed from libsocket on Solaris 8 */
diff --git a/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c
new file mode 100644
index 0000000..2384151
--- /dev/null
+++ b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c
@@ -0,0 +1,62 @@
+/*
+ * 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 <jni.h>
+#include <string.h>
+
+#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/jdk/test/TEST.groups b/jdk/test/TEST.groups
index 77fae72..c3b43e6 100644
--- a/jdk/test/TEST.groups
+++ b/jdk/test/TEST.groups
@@ -103,7 +103,8 @@
java/net \
com/sun/net \
com/oracle/net \
- sun/net
+ sun/net \
+ jdk/net
jdk_time = \
java/time
diff --git a/jdk/test/jdk/net/Sockets/Test.java b/jdk/test/jdk/net/Sockets/Test.java
new file mode 100644
index 0000000..81ed76a
--- /dev/null
+++ b/jdk/test/jdk/net/Sockets/Test.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ *
+ * 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 8032808
+ * @run main/othervm -Xcheck:jni Test
+ * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail
+ * @run main/othervm/policy=policy.success -Xcheck:jni Test success
+ */
+
+import java.net.*;
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import jdk.net.*;
+
+public class Test {
+
+ static boolean security;
+ static boolean success;
+
+ interface Runner {
+ public void run() throws Exception;
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ // quick check to see if supportedOptions() working before
+ // creating any sockets and libnet loaded
+
+ Sockets.supportedOptions(Socket.class);
+
+ security = System.getSecurityManager() != null;
+ success = security && 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);
+ }
+
+ 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();
+
+ 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));
+
+ // Do some standard options tests first. Since JDK 8 doesn't have java.net API
+ Sockets.setOption(s, StandardSocketOptions.SO_SNDBUF, 8000);
+ System.out.println ("Set SO_SNDBUF to 8000\ngetting returns: ");
+ System.out.println (Sockets.getOption(s, StandardSocketOptions.SO_SNDBUF));
+
+ Sockets.setOption(ss, StandardSocketOptions.SO_RCVBUF, 5000);
+ System.out.println ("Set SO_RCVBUF to 5000\ngetting returns: ");
+ System.out.println (Sockets.getOption(s, StandardSocketOptions.SO_RCVBUF));
+
+ try {
+ Sockets.setOption(ss, StandardSocketOptions.TCP_NODELAY, true);
+ throw new RuntimeException("TCP_NODELAY should not be supported for ServerSocket");
+ } catch (UnsupportedOperationException e) {}
+ try {
+ Sockets.setOption(dg, StandardSocketOptions.IP_MULTICAST_LOOP, true);
+ throw new RuntimeException("IP_MULTICAST_LOOP should not be supported for DatagramSocket");
+ } catch (UnsupportedOperationException e) {}
+
+ MulticastSocket mc0 = new MulticastSocket(0);
+ Sockets.setOption(mc0, StandardSocketOptions.IP_MULTICAST_LOOP, true);
+ System.out.println ("Expect true: " + Sockets.getOption(mc0, StandardSocketOptions.IP_MULTICAST_LOOP));
+
+ // Now the specific tests for SO_FLOW_SLA
+
+ 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<Void> f = asc.connect(loopad);
+ f.get();
+ asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+ });
+ }
+
+ static void doTest(Runner func) throws Exception {
+ try {
+ func.run();
+ if (security && !success) {
+ throw new RuntimeException("Test failed");
+ }
+ } catch (SecurityException e) {
+ if (success) {
+ throw new RuntimeException("Test failed");
+ }
+ } catch (UnsupportedOperationException e) {}
+ }
+}
diff --git a/jdk/test/jdk/net/Sockets/policy.fail b/jdk/test/jdk/net/Sockets/policy.fail
new file mode 100644
index 0000000..29d1215
--- /dev/null
+++ b/jdk/test/jdk/net/Sockets/policy.fail
@@ -0,0 +1,4 @@
+grant {
+ permission java.net.SocketPermission "127.0.0.1", "connect,accept" ;
+ permission java.net.SocketPermission "localhost", "listen" ;
+};
diff --git a/jdk/test/jdk/net/Sockets/policy.success b/jdk/test/jdk/net/Sockets/policy.success
new file mode 100644
index 0000000..6f99151
--- /dev/null
+++ b/jdk/test/jdk/net/Sockets/policy.success
@@ -0,0 +1,6 @@
+grant {
+ permission java.net.SocketPermission "127.0.0.1", "connect,accept" ;
+ permission java.net.SocketPermission "localhost", "listen" ;
+ permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA";
+ permission jdk.net.NetworkPermission "getOption.SO_FLOW_SLA";
+};